Repository navigation
fix: read RAVEN 3 model files, and tolerate a non-double rev - #759
Conversation
RAVEN 3 and raven-toolbox write YAML this version cannot read. The
metaData map is tagged (`- metaData: !!omap`), which the exact-match case
missed, so the whole block was skipped and the model came back with no
id, name, version or date. A reaction's free text moved from `rxnNotes`
to `notes`, which aborted the read outright with "Unknown entry in yaml
file". EC codes and SMILES moved inside the per-entry `annotation` block,
where they were gathered as MIRIAMs instead of filling eccodes and
metSmiles. An empty gene list is written inline, and the GECKO flag is
spelled `gecko_light`.
All of these are accepted on read now; what this version writes is
unchanged, so its own output stays valid for older RAVEN.
importModel also only found a model note inside a <body>, which RAVEN's
exportModel writes but a writer serialising a notes dictionary does not;
such a writer emits one "<p>key: value</p>" per entry, so the labelled
entry is taken when there is one and the <body> text otherwise.
mergeLinear combines rev with a sparse logical, which MATLAB refuses for
an integer class ("Sparse integer array arithmetic operations are not
supported"). A model built outside RAVEN can carry an integer rev, so it
is coerced once on entry rather than failing several steps into ftINIT.
metComps is documented as an integer column: a reader that turns the
1-based index into a position needs an integer, and MATLAB stores an
integer-valued double narrowed to an integer type in any case.
updateDocumentation regenerates the whole doc/ tree, but the committed files were generated on Windows and every other one differs only in the path separator of its index link and title (external\kegg vs external/kegg). Only the three functions this branch changes are updated, so the diff stays about the change rather than about the platform it was regenerated on.
The earlier fix coerced reducedModel.rev to double on entry to
mergeLinear, which changed the class of rev in the model it returns --
a type the caller did not ask to have changed.
Comparing instead matches what every other use of rev in RAVEN already
does (rev == 1, rev ~= 0, find(rev)), works for a double, an integer or a
logical alike, and leaves the model untouched. On the released Human-GEM
2.1.0 .mat, whose rev is int64, both forms return the same 8751
reactions with the same S and the same rev values, but the comparison
leaves rev as int64 instead of silently making it double.
ftINIT had the same pattern and the same failure:
any(prepData.refModel.S(metSel,:) < 0,1) & prepData.refModel.rev.'
a sparse logical combined with rev, which MATLAB refuses for an integer
array. It only runs when metabolomics data is supplied, which is why
#1143 did not reach it. Every other use of rev compares first and is
already class-agnostic.
|
Revised the I tested every pattern Two changes follow.
Comparing is better than coercing. The previous commit set On the released Human-GEM 2.1.0 Same result either way, but |
Lets RAVEN 2 read model files written by RAVEN 3 and raven-toolbox, so RAVEN 2 functionality stays usable against current models. Proposed for a 2.11.4 patch release.
Prompted by SysBioChalmers/Human-GEM#1143, where a user on RAVEN 2.11.3 could reach Human-GEM 2.1.0 through none of its formats.
What RAVEN 2 could not read
All in
io/readYAMLmodel.m, measured against the released Human-GEM 2.1.0 YAML:- metaData: !!omapid,name,versionordate, silentlynotes:rxnNoteswas a case in the reactions section, so the read aborted:Unknown entry in yaml file: - notes: PXMP2 forms a non-selective pore...ec-codeinsideannotationeccodes, which came back emptysmilesinsideannotationmetSmiles- genes: []gecko_lightgeckoLightwas acceptedThe first two are what blocked Human-GEM 2.1.0 outright.
Read tolerance only. What this version writes is unchanged — it still emits
rxnNotesand an untaggedmetaData— so RAVEN 2 output stays valid for older RAVEN, and this stays a patch-sized change.importModel: the model note
importModellooked for the note betweenxhtml">and</body>. RAVEN's ownexportModelwrites that, but a writer serialising a notes dictionary emits one<p>key: value</p>per entry and no<body>at all, carrying the note under its own key. The labelled entry is now taken when there is one — so the other entries (version, and whatever else the dictionary held) stay out of the note — falling back to the<body>text otherwise.mergeLinear: an integer rev
mergeLinearcombinesrevwith a sparse logical:MATLAB rejects that for an integer class —
Sparse integer array arithmetic operations are not supported— and a model built outside RAVEN can easily carry an integerrev(cobrapy'ssave_matlab_modelwritesnp.array(reversibility) * 1, which isint64on Linux/macOS). Coerced once on entry rather than failing several steps into ftINIT.metComps
Documented as an integer column rather than a double. A reader that turns the 1-based index into a position needs an integer, and MATLAB's own
savenarrows an integer-valued double to an integer type on disk in any case; both classes indexcompsidentically.Verification
MATLAB R2024b on Vera, against the released Human-GEM files.
Human-GEM 2.1.0 YAML, previously a hard abort:
Model note through SBML:
mergeLinearon the released Human-GEM 2.1.0.mat, whoserevisint64:The
.matitself is fixed separately in CompMetEng/raven-toolbox#168; this change means RAVEN 2 survives the files already published.