From dbf14b0309ceea0c2ab8a2ab8d946284e25ec7c7 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Wed, 9 Sep 2026 17:36:42 +0200 Subject: [PATCH 1/4] Site polish: install steps, page moves, and two real bugs on the migration guide Small batch of feedback after the pydata-sphinx-theme switch. - index.md: the pip install had no --pre, so it would refuse to install the current 3.0.0b1 pre-release; the MATLAB installs never mentioned checkRaven to verify. - migrate.md / parameter-tuning/index.md: the YAML model format page was filed under Migrate, but it is a file-format reference, not a version/language migration; moved it under Methods. - raven3-vs-raven-toolbox.md: "Confidence tracking" and the newer assignCompartments were listed as shipped raven-toolbox-only capabilities; both are still WIP. "Scope: reconstruction and analysis" was filed under "What only RAVEN has", but it describes ground RAVEN and raven-toolbox share against the COBRA Toolbox, not a RAVEN-only capability. - raven3-migration.md: no summary at the top for a reader who reads nothing else. Several headings carried a leftover MkDocs-style anchor with no href; pydata-sphinx-theme's sidebar-toggle script iterates every in-page anchor and calls getAttribute("href").startsWith(...) on each, so the null href threw and aborted the rest of the script's init, including the collapse-sidebar button's own click handler, on this page only. Several of those anchor names also didn't match MyST's auto-generated heading id (kegg-reconstruction, sbml-io, excel-io, and others), which is why guide/io.md's links into this page were already warning at build time. - _static/custom.css: tables have no upper bound on width under table-layout: auto, and one long comma-separated identifier list rendered as a single non-wrapping .pre span was enough to force a table to nearly twice the width of the article column. --- docs/_static/custom.css | 22 ++++++++++++++ docs/index.md | 7 +++-- docs/migrate.md | 4 +-- docs/parameter-tuning/index.md | 7 +++++ docs/raven3-migration.md | 51 ++++++++++++++++++++++++--------- docs/raven3-vs-raven-toolbox.md | 32 --------------------- 6 files changed, 73 insertions(+), 50 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 0d3a71a..877fa98 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -22,6 +22,28 @@ border: 0; } +/* ===== Tables: fit the article column instead of forcing a horizontal + scrollbar. table-layout:auto sizes a table from its content's preferred + width with no upper bound; capping it at the container's width makes long + cells wrap instead of pushing the table wider than the page. ============ */ +.bd-article table { + table-layout: fixed; + width: 100%; + max-width: 100%; +} +.bd-article table td, +.bd-article table th { + overflow-wrap: break-word; +} +/* Sphinx wraps inline code in a single white-space:nowrap span, which is + right in prose but lets one long identifier list force a table cell wide. + Table cells are the one place breaking a code token mid-word is better + than the cell (and the whole table) overflowing. */ +.bd-article table code .pre { + white-space: normal; + overflow-wrap: break-word; +} + /* ===== Home page logo: swap for the dark scheme ======================= */ .rh-logo-light, .rh-logo-dark { max-width: 420px; diff --git a/docs/index.md b/docs/index.md index bbba9ef..d4d6c7c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,12 +14,13 @@ models, available as a MATLAB toolbox and a Python package built on cobrapy. :::{tab-item} Python (pip) ```bash -pip install raven-toolbox +pip install --pre raven-toolbox ``` ::: :::{tab-item} MATLAB (Add-Ons) -Home → Add-Ons → Get Add-Ons → search "RAVEN Toolbox" +Home → Add-Ons → Get Add-Ons → search "RAVEN Toolbox", then run `checkRaven` +to verify. ::: :::{tab-item} Python (git) @@ -33,6 +34,8 @@ pip install -e raven-toolbox/ ```bash git clone --depth=1 https://github.com/SysBioChalmers/RAVEN.git ``` + +Add the folder to the MATLAB path, then run `checkRaven` to verify. ::: :::: diff --git a/docs/migrate.md b/docs/migrate.md index 27ae964..deff839 100644 --- a/docs/migrate.md +++ b/docs/migrate.md @@ -4,7 +4,7 @@ icon: material/folder-open # Migrate -Four ways of moving between versions or languages, each answering a +Three ways of moving between versions or languages, each answering a different question. | | | @@ -12,7 +12,6 @@ different question. | [RAVEN 2 → RAVEN 3 (MATLAB)](raven3-migration.md) | Upgrading an existing MATLAB codebase: what was renamed, removed outright, or changed between RAVEN 2 and RAVEN 3. | | [RAVEN 3 → raven-toolbox](raven3-vs-raven-toolbox.md) | Choosing between the two current implementations, or porting a MATLAB workflow to Python: what each toolbox has, and where they answer the same question differently. | | [MATLAB vs Python function mapping](matlab-vs-python.md) | The full name table pairing every function that exists in both, generated at build time from both toolboxes' sources. | -| [Model file format (YAML)](yaml-format.md) | The YAML model format cobrapy, raven-toolbox and RAVEN MATLAB all read and write, for moving a model file between any of them or into version control. | ```{toctree} :hidden: @@ -20,5 +19,4 @@ different question. raven3-migration raven3-vs-raven-toolbox matlab-vs-python -yaml-format ``` diff --git a/docs/parameter-tuning/index.md b/docs/parameter-tuning/index.md index 591cf2e..6e3a7d4 100644 --- a/docs/parameter-tuning/index.md +++ b/docs/parameter-tuning/index.md @@ -99,11 +99,18 @@ cross-toolbox to-do list. |---|---| | [Parameter benchmarks](benchmarks.md) | `fseof`, `remove_genes`, `connect_blocked_reactions`, `fill_gaps_*`, `check_tasks`, `find_task_essential_reactions` | +## Model file format + +[YAML model format](../yaml-format.md): the format cobrapy, raven-toolbox and +RAVEN MATLAB all read and write, for moving a model file between any of them +or into version control. + ```{toctree} :hidden: ../tuned-parameters benchmarks +../yaml-format ``` ```{toctree} diff --git a/docs/raven3-migration.md b/docs/raven3-migration.md index bd7dcb6..736ed4a 100644 --- a/docs/raven3-migration.md +++ b/docs/raven3-migration.md @@ -1,5 +1,17 @@ # Migrating from RAVEN 2 to RAVEN 3 +:::{admonition} If you read nothing else +:class: important + +Run `checkRaven` (replaces `checkInstallation`) right after upgrading: it +offers to fetch any missing on-demand binaries/data, and its checks catch +several of the changes below before your scripts do. Beyond that, the two +changes most likely to break silently rather than error are homology/KEGG +reconstruction returning a different draft model from the same call +([§7](#kegg-reconstruction)), and WoLF PSORT-based localization scores having +no in-toolbox migration path ([§3](#backward-incompatible-changes)). +::: + This guide describes what changed between RAVEN 2 and RAVEN 3. It is written for existing RAVEN 2 users who need to know what will break in their scripts, what moved, what was removed outright, and what new capabilities are @@ -33,7 +45,8 @@ punch list. The sections after it go into the detail behind each item. --- -## Upgrade checklist +(upgrade-checklist)= +## Upgrade checklist 1. Update to RAVEN 3.0.0 (or later) and run `checkRaven` (replaces `checkInstallation`); it will offer to fetch any missing on-demand @@ -155,7 +168,8 @@ names, use the explicit name-value form for that argument to avoid ambiguity. --- -## 3. Backward-incompatible changes +(backward-incompatible-changes)= +## 3. Backward-incompatible changes This is the consolidated list of everything a RAVEN 2 script could plausibly break on, or silently produce different output from, when run against RAVEN 3. @@ -242,7 +256,8 @@ an air-gapped install, and the full dependency comparison. --- -## 4. Removed functionality +(removed-functionality)= +## 4. Removed functionality Beyond the items already listed as backward-incompatible above, RAVEN 3 removed a number of functions and whole subsystems as part of a deliberate "leaner @@ -271,7 +286,8 @@ codebase" push. None of these have call sites left in RAVEN 3 itself. --- -## 5. Renamed, merged, and consolidated functions +(renamed-merged-and-consolidated-functions)= +## 5. Renamed, merged, and consolidated functions RAVEN 3 introduces a formal **`deprecated/` folder convention**: functions that were merged into a more general replacement stay callable under their old name, @@ -300,9 +316,11 @@ them. --- -## 6. File formats and model I/O +(file-formats-and-model-io)= +## 6. File formats and model I/O -### SBML I/O +(sbml-io)= +### SBML I/O | | RAVEN 2 | RAVEN 3 | |---|---|---| @@ -313,7 +331,8 @@ them. Older SBML files must be converted first (e.g. re-exported from COBRApy/COBRA Toolbox) before `importModel` will accept them. -### Excel I/O +(excel-io)= +### Excel I/O | | RAVEN 2 | RAVEN 3 | |---|---|---| @@ -343,7 +362,8 @@ model files: | Empty `gene_reaction_rule` | written as an empty string | omitted | | `objective_coefficient` on import | ignored | honored | -### RAVEN⇄COBRA interoperability +(raven-cobra-interoperability)= +### RAVEN⇄COBRA interoperability `conversion/ravenCobraWrapper.m` keeps its signature (`newModel = ravenCobraWrapper(model)`) unchanged. Two correctness fixes change @@ -354,7 +374,8 @@ annotation conversion; both fixed. --- -## 7. Reconstruction: KEGG and homology pipelines +(kegg-reconstruction)= +## 7. Reconstruction: KEGG and homology pipelines ### KEGG-based reconstruction (`getModelFromKEGG`, `getKEGGModelForOrganism`) @@ -391,7 +412,8 @@ mapping table. --- -## 8. Gene-reaction-rule (GPR) parsing +(gpr-parsing)= +## 8. Gene-reaction-rule (GPR) parsing RAVEN 3 adds a proper grRule tokenizer/parser: `utils/parseGrRule.m` builds a parse tree (`type`: `'gene'|'and'|'or'`, with `children`); `utils/grRuleToDNF.m` @@ -417,7 +439,8 @@ string-splitting logic it always did. --- -## 9. Gap-filling and context-specific model extraction +(ftinit)= +## 9. Gap-filling and context-specific model extraction | | RAVEN 2 | RAVEN 3 | |---|---|---| @@ -433,7 +456,8 @@ string-splitting logic it always did. --- -## 10. New functionality +(new-functionality)= +## 10. New functionality All additive; none of this replaces or changes behavior of existing RAVEN 2 functions, except where noted. @@ -453,7 +477,8 @@ functions, except where noted. --- -## 11. Toolbox dependencies and installation +(toolbox-deps)= +## 11. Toolbox dependencies and installation | | RAVEN 2 | RAVEN 3 | |---|---|---| diff --git a/docs/raven3-vs-raven-toolbox.md b/docs/raven3-vs-raven-toolbox.md index 1a39418..e852049 100644 --- a/docs/raven3-vs-raven-toolbox.md +++ b/docs/raven3-vs-raven-toolbox.md @@ -77,24 +77,6 @@ distance matrix. RAVEN consumes pre-built artefacts; it does not produce them. This is what keeps the KEGG route reproducible against a stated KEGG release rather than against whichever artefact is currently distributed. -### Confidence tracking - -Per-reaction, multi-facet confidence scoring: evidence for a reaction's presence -graded across several independent facets, with the bands calibrated against -curated models. Used to prioritise manual curation on a draft: reactions the -score is least sure about are where a curator's time goes furthest. - -### A newer compartment assignment - -Both toolboxes have `assignCompartments`, and they are **not** the same -function. RAVEN's is a port of raven-toolbox's earlier design, in which -functionality is fused into the placement MILP as a hard flux-gating -constraint. raven-toolbox has since separated the two: placement is decided by a -score MILP, then *certified* by a real FBA on the materialised model, so a -placement that breaks biomass production is rejected rather than returned. It -can couple gap-filling into that loop, and keeps a second compartment for a -reaction only when a loopless FVA shows it carries flux there. - ### Smaller additions - **Growth conditions**: apply a named, versioned growth condition to a model. @@ -126,20 +108,6 @@ has to be reproduced in MATLAB; see structures. There is nothing to convert in Python: the model is already a `cobra.Model`, so no equivalent exists or is needed. -### Scope: reconstruction and analysis - -RAVEN's functions concentrate on **reconstruction**: building a model from a -genome by homology or from KEGG, extracting a context-specific one from -expression data, gap-filling it, and validating it against metabolic tasks. Its -analysis functions cover what those steps require. - -The COBRA Toolbox covers more **analysis**: thermodynamic constraints, -strain-design algorithms such as OptKnock and OptForce, community and whole-body -models, and further sampling and loopless variants. RAVEN does not reimplement -them. `ravenCobraWrapper` converts a RAVEN model into COBRA Toolbox form, and a -raven-toolbox model is already a `cobra.Model`, so both are direct inputs to -those analyses. - ### Dynamic FBA `runDynamicFBA` has no Python counterpart, deliberately. Several maintained From 295162a0e8e21d5351c884edc91803f236448107 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Wed, 9 Sep 2026 18:28:50 +0200 Subject: [PATCH 2/4] Direct prose sweep, plus title, content, and installation fixes Two rounds of feedback: a site-wide sweep for idiomatic and headline-style phrasing (many readers are non-native English speakers), and a batch of title, content, and factual fixes. - CLAUDE.md (new): documents the no-idiom/no-headline-fragment prose rule for future edits, with the two flagged examples. - Site-wide sweep: dozens of headings and sentences across docs/guide/, docs/parameter-tuning/, docs/protocol/, docs/tutorials/, and the top-level pages relied on implied grammar or figurative language ("same verdicts, very different cost", "the cost of a deletion", "a gold standard", "showed its age", "drift apart") instead of stating the point directly. - docs/guide/index.md, docs/index.md, docs/parameter-tuning/index.md, docs/references.md: "User guide", "Methods", and "References" named the tab by category instead of content; renamed to "Guide", "Parameter tuning", and "Citations". The Guide's own sidebar captions ("Install", "Functions") had the same problem; renamed to "Installation" and "Task pages". - docs/guide/fba.md, docs/guide/media.md: loaded yeast-GEM.xml over SBML when the same model already ships as yeast-GEM.yml, needing an extra import path and printing two SBML-reader warnings unrelated to either page's actual topic. - docs/raven3-vs-raven-toolbox.md: the "What identical results means" section restated general MILP/statistical-comparison background already covered elsewhere on the page; removed. The elemental balance explanation didn't say what "balanced" means or why the unknown case matters; rewritten. The solvers table said MATLAB's GLPK comes via the COBRA Toolbox; it ships bundled with RAVEN itself. - docs/installation/raven.md: solver setup (Gurobi license/savepath, COBRA Toolbox integration, setRavenSolver's valid values), the addRavenToUserPath fallback for managed installs, and checkInstallation's rename to checkRaven were all on the RAVEN wiki's installation page but missing here; added. Two headings used an inline "{ #id }" attribute the site's Markdown flavor doesn't support, so the ids never applied and three "verify the installation" links pointed at nothing; fixed to real anchors. - scripts/gen_api_pages_sphinx.py, docs/matlab-vs-python.md: the cobrapy-covered functions sat in a separate, badge-less section instead of the main pairs table; merged in, marked with a linked cobrapy badge. --- CLAUDE.md | 28 ++++ docs/api/index.md | 4 +- docs/guide/biomass.md | 7 +- docs/guide/combining.md | 9 +- docs/guide/comparing.md | 3 +- docs/guide/deletions.md | 9 +- docs/guide/editing.md | 2 +- docs/guide/engineering.md | 15 +- docs/guide/fba.md | 16 +-- docs/guide/fva.md | 10 +- docs/guide/getting-started.md | 2 +- docs/guide/homology.md | 8 +- docs/guide/index.md | 16 +-- docs/guide/init.md | 9 +- docs/guide/io.md | 18 +-- docs/guide/kegg.md | 7 +- docs/guide/media.md | 12 +- docs/guide/model-structure.md | 2 +- docs/guide/sampling.md | 10 +- docs/guide/solvers.md | 4 +- docs/guide/tasks.md | 10 +- docs/index.md | 4 +- docs/installation/raven.md | 85 ++++++++++-- docs/parameter-tuning/benchmarks.md | 6 +- docs/parameter-tuning/index.md | 13 +- .../studies/ftinit-determinism.md | 2 +- .../studies/homology-cutoff-calibration.md | 16 +-- .../studies/init-param-calibration.md | 16 +-- .../studies/kegg-hmm-cutoff-calibration.md | 2 +- .../sampling-convergence-calibration.md | 14 +- docs/protocol/anticipated-results.md | 2 +- docs/protocol/index.md | 5 +- docs/raven3-migration.md | 24 ++-- docs/raven3-vs-raven-toolbox.md | 129 ++++++------------ docs/references.md | 2 +- docs/tuned-parameters.md | 2 +- docs/tutorials/index.md | 11 +- docs/tutorials/tutorial1.md | 6 +- docs/tutorials/tutorial4.md | 4 +- scripts/gen_api_pages_sphinx.py | 52 ++++--- 40 files changed, 330 insertions(+), 266 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..88b5758 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,28 @@ +# raven-docs + +## Documentation prose style + +This site's readers are not all native English speakers. Prose has to be +direct and literal, not just factually correct. + +No idioms, figures of speech, or headline-style fragments that drop the +subject or verb for effect. A heading or sentence should parse the same way +for a reader translating it word by word as it does for a native speaker. +Two examples flagged and rewritten in a live sweep of this repo: + +- "Names do not convert mechanically" (a heading) implies its meaning through + word choice ("mechanically" standing in for "automatically" or "by a fixed + rule") rather than stating it. +- "Same verdicts, very different cost" (a heading) is a sentence fragment: the + subject and verb are implied, not written, and the reader has to supply + "they give" and "but they have" to parse it. + +Rewrite this kind of phrasing as a complete, literal sentence that says what +it means. Direct is not the same as dumbed down: keep the technical content +and the precision, drop only the cleverness. + +No em dashes, anywhere: not in prose, headings, table cells, or generated +strings. Use the punctuation the sentence calls for instead: a comma where +the clause continues, a semicolon where it is independent, a colon where +what follows defines or enumerates what precedes it, parentheses for a +matched pair around an aside. diff --git a/docs/api/index.md b/docs/api/index.md index 8881325..f268bb2 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -33,10 +33,10 @@ To move between the two implementations, use the **[MATLAB vs Python](../matlab- table, which pairs every function that exists in both (`camelCase` ↔ `snake_case`) and links to both references. -## How the two line up +## How the two compare The implementations are deliberately kept aligned. The main differences are -mechanical: +in calling convention, not in what the functions compute: | | RAVEN (MATLAB) | raven-toolbox (Python) | |---|---|---| diff --git a/docs/guide/biomass.md b/docs/guide/biomass.md index 3dd130f..3dbd1f6 100644 --- a/docs/guide/biomass.md +++ b/docs/guide/biomass.md @@ -176,9 +176,10 @@ representation. ## 22.2 Change one component -Measured a different protein content? Set it, and say what gives way. A biomass -that no longer sums to 1 is worse than one with the old number in it, so both -functions can balance a second component to absorb the difference. +Measured a different protein content? Set it, and specify which other component +absorbs the change. A biomass that no longer sums to 1 is worse than one with the +old number in it, so both functions can balance a second component to absorb the +difference. ::::{tab-set} :::{tab-item} Ⓜ️ MATLAB diff --git a/docs/guide/combining.md b/docs/guide/combining.md index badd94c..0d27c60 100644 --- a/docs/guide/combining.md +++ b/docs/guide/combining.md @@ -1,6 +1,7 @@ # 16. Combining and simplifying models -Two operations that look like bookkeeping and are not. **Merging** puts models +This page covers two operations that look like simple bookkeeping but carry real +risk. **Merging** puts models together: a draft and a template, two organisms, a curated core and an extension, and the result is only as sound as the assumption that a metabolite in one model is the same molecule as in the other. **Simplifying** takes a model @@ -20,8 +21,8 @@ you needed. ## Setup `smallYeast.yml`, and a second model to merge it with. Taking a copy and giving -it a new id keeps the example honest: whatever the merge does to two identical -models is the clearest possible statement of what it matches on. +it a new id makes the comparison unambiguous: whatever the merge does to two +identical models is the clearest possible statement of what it matches on. ::::{tab-set} :::{tab-item} Ⓜ️ MATLAB @@ -114,7 +115,7 @@ way, without a warning. Matching on id is the right choice when both models come from the same database, where the ids mean the same thing and the names may not. -:::{warning} Names, not identifiers +:::{warning} Merging matches on names, not identifiers Two models built from different databases usually share almost no metabolite **names** either, in which case merging produces a model with two disconnected halves that happen to live in the same struct. Merging is a claim that the diff --git a/docs/guide/comparing.md b/docs/guide/comparing.md index 8b2a969..685f333 100644 --- a/docs/guide/comparing.md +++ b/docs/guide/comparing.md @@ -209,7 +209,8 @@ growth: good 0.1222, bad 0.0000 The errors in `smallYeastBad` are not cosmetic. On the same medium, with the same objective, the good model grows and **the bad one does not grow at all**, from a model that a set-overlap score called 94.5 % similar. A diff tells you the models -differ; only a simulation tells you what the difference costs. (MATLAB reports +differ; only a simulation tells you what effect the difference has on growth. +(MATLAB reports that zero as `-0.0000`; the minus sign is a formatting artefact of a zero objective, not a negative growth rate.) diff --git a/docs/guide/deletions.md b/docs/guide/deletions.md index 80d94b0..b3e421f 100644 --- a/docs/guide/deletions.md +++ b/docs/guide/deletions.md @@ -11,7 +11,7 @@ distribution better than plain FBA does". |---|---|---| | `findGeneDeletions` | `single_gene_deletion` {bdg-secondary}`cobrapy` | knock out every gene in turn | | `findGeneDeletions` (`'sgd'`/`'dgd'`) | `double_gene_deletion` {bdg-secondary}`cobrapy` | pairs of genes | -| `getEssentialRxns` | `find_task_essential_reactions` | reactions a task cannot do without | +| `getEssentialRxns` | `find_task_essential_reactions` | reactions a task requires | | `deleteUnusedGenes` | `remove_genes` | remove genes, rather than knock them out | | no equivalent | `moma` {bdg-secondary}`cobrapy` | a knockout's fluxes, staying near the wild type | @@ -152,7 +152,8 @@ because the same function shape serves the double-deletion case. ## 11.3 Essential reactions Reaction essentiality asks the same question one level down. The two functions -below look equivalent and are not, which is why their answers differ by 24. +below look equivalent but ask different questions, which is why their answers +differ by 24. ::::{tab-set} :::{tab-item} Ⓜ️ MATLAB @@ -204,8 +205,8 @@ raven-toolbox has `find_task_essential_reactions`; see ## 11.4 Two at a time Double deletions find the redundancy single deletions miss: two genes that each -look dispensable but cannot both go. The cost is quadratic in the number of -genes, so run time grows sharply with model size. +look dispensable but cannot both be deleted. The number of pairs to test is +quadratic in the number of genes, so run time grows sharply with model size. ::::{tab-set} :::{tab-item} Ⓜ️ MATLAB diff --git a/docs/guide/editing.md b/docs/guide/editing.md index 2e77f40..d5e3a33 100644 --- a/docs/guide/editing.md +++ b/docs/guide/editing.md @@ -250,7 +250,7 @@ with model: ``` `remove_orphans=True` is cobrapy's equivalent of those two flags. Note the -`with model:`, deletions inside it are rolled back on exit, so the cost of +`with model:`, deletions inside it are rolled back on exit, so the effect of a deletion can be measured without keeping it. ::: :::: diff --git a/docs/guide/engineering.md b/docs/guide/engineering.md index 592bca9..9b01c87 100644 --- a/docs/guide/engineering.md +++ b/docs/guide/engineering.md @@ -1,9 +1,10 @@ # 20. Engineering targets -Two questions sit behind most strain-design work. Which reactions would have to -change for the cell to make more of something, and which metabolites sit at the -centre of a transcriptional response. FSEOF answers the first from stoichiometry -alone; reporter metabolites answer the second from expression data. +Two questions underlie most strain-design work. Which reactions would have to +change for the cell to make more of something, and which metabolites are most +affected by a transcriptional response. FSEOF answers the first from +stoichiometry alone; reporter metabolites answer the second from expression +data. ### Functions on this page @@ -132,7 +133,7 @@ zero. ## 20.2 Reading the scan -A target is only as good as the trend behind it. The scan matrix is what +A target's reliability depends on the trend behind it. The scan matrix is what distinguishes a reaction that rises steadily from one that jumps once and stops. ::::{tab-set} @@ -289,8 +290,8 @@ above. nothing is differentially expressed. Look at the input distribution before trusting the ranking. - **Currency metabolites at the top.** ATP, NADH and water take part in a - large share of all reactions, so they surface easily. Excluding them, or - reading past them, is usually necessary. + large share of all reactions, so they appear at the top easily. Excluding + them, or reading past them, is usually necessary. ::: ## See also diff --git a/docs/guide/fba.md b/docs/guide/fba.md index 0c71b59..446c433 100644 --- a/docs/guide/fba.md +++ b/docs/guide/fba.md @@ -21,7 +21,7 @@ Every simulation step on this page is cobrapy, marked ## Setup -`yeast-GEM.xml` from [`docs/data/`](../data/README.md), yeast-GEM v9.1.0, which +`yeast-GEM.yml` from [`docs/data/`](../data/README.md), yeast-GEM v9.1.0, which arrives with a growth objective and an aerobic glucose medium already set. ## 4.1 Solve @@ -31,7 +31,7 @@ arrives with a growth objective and an aerobic glucose medium already set. :sync: matlab ```matlab -model = importModel('yeast-GEM.xml'); +model = readYAMLmodel('yeast-GEM.yml'); sol = solveLP(model); fprintf('objective: %s\n', model.rxns{model.c == 1}); fprintf('status: %d\n', sol.stat); @@ -39,17 +39,13 @@ fprintf('growth: %.4f /h\n', sol.f); ``` ```text -[Warning: The following fields have prefixes removed from all entries. If this is undesired, run importModel with removePrefix as false. Example: importModel('filename.xml',[],false);] -[Warning: The following MIRIAM strings are associated to more than one unique metabolite name: bigg.metabolite/ficytb5 bigg.metabolite/hdd2coa bigg.metabolite/pail_cho bigg.metabolite/pchol_cho bigg.metabolite/succ bigg.metabolite/tchola chebi/CHEBI:138108 chebi/CHEBI:17140 chebi/CHEBI:18097 ...and 23 more] objective: r_2111 status: 1 growth: 0.0809 /h ``` The objective is `model.c`, a vector with one entry per reaction, so -`model.c == 1` finds the reaction being maximised. The two warnings come from -the reader, not the solve; [3. Reading and writing models](io.md) explains -both. +`model.c == 1` finds the reaction being maximised. `sol` carries the whole answer. `sol.f` is the objective value with its natural sign: RAVEN minimises internally and negates the result, so no sign @@ -72,9 +68,9 @@ LP dual. :sync: python ```python -from cobra.io import read_sbml_model +from raven_toolbox.io import read_yaml_model -model = read_sbml_model("yeast-GEM.xml") +model = read_yaml_model("yeast-GEM.yml") solution = model.optimize() print(f"objective: {model.objective.expression}") @@ -344,7 +340,7 @@ total flux: 100.6 ``` `minFlux` selects the second optimisation. `1` minimises the sum of absolute -fluxes, which costs one further LP. `3` +fluxes, which requires one further LP. `3` minimises the *number* of active reactions instead, which is a mixed-integer problem: the result is easier to read as a pathway, and the solve is far slower. Leaving `minFlux` at `0` skips the second solve diff --git a/docs/guide/fva.md b/docs/guide/fva.md index 0853712..fe2ea42 100644 --- a/docs/guide/fva.md +++ b/docs/guide/fva.md @@ -1,9 +1,9 @@ # 14. Flux variability and alternative optima An FBA solution is one point in a space of equally optimal answers. Flux -variability asks the more honest question: **given the objective, how much can -each reaction's flux still vary?** It is how you tell a flux the model insists on -from one it merely happened to report. +variability asks the more accurate question: **given the objective, how much can +each reaction's flux still vary?** It is how you distinguish a flux the model +requires from one it merely happened to report. ### Functions on this page @@ -149,7 +149,7 @@ land on. ## 14.3 A wide range is not always a real one -A reaction can show a wide range purely because it sits in a thermodynamically +A reaction can show a wide range purely because it is part of a thermodynamically infeasible cycle, flux going round a loop with no net driving force. The widest span in 14.1 was 1000, the model's default bound. That span is such a cycle. @@ -242,7 +242,7 @@ growth: 0.1222 /h, total flux: 20.9 `minFlux` minimises total absolute flux subject to the objective, which is parsimonious FBA. It is also the closest RAVEN gets to excluding loops: a -cycle costs flux, so a parsimonious solution has no reason to carry one. +cycle adds flux, so a parsimonious solution has no reason to carry one. ::: :::{tab-item} 🐍 Python :sync: python diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 502e2fa..13e3ded 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -336,7 +336,7 @@ decide, so an empty result covers both "balanced" and "nothing to check". ## See also -- [User guide overview](index.md), the other pages, and what is still planned. +- [Guide overview](index.md), the other pages, and what is still planned. - [MATLAB vs Python](../raven3-vs-raven-toolbox.md), what each toolbox has, and where cobrapy takes over. - [API reference](../api/index.md), every function in both toolboxes. diff --git a/docs/guide/homology.md b/docs/guide/homology.md index 621a83e..55c02a4 100644 --- a/docs/guide/homology.md +++ b/docs/guide/homology.md @@ -8,7 +8,7 @@ each template reaction whose genes have an accepted match is copied across. The work happens in two steps: a sequence search that produces a table of hits, and a transfer step that decides which of those hits are good enough to carry a reaction. The cut-offs used by the second step determine the size and the -reliability of the draft, and they are where the method's assumptions sit. +reliability of the draft, and they are what encode the method's assumptions. ### Functions on this page @@ -125,7 +125,7 @@ The shape of the result differs between the toolboxes. RAVEN returns a struct array with one entry per direction, each carrying `fromId`, `toId`, `fromGenes`, `toGenes` and per-hit `evalue`, `aligLen` and `identity` vectors. raven-toolbox returns a single `pandas` DataFrame with `from_id` and `to_id` columns, so both -directions sit in one table and can be filtered with ordinary DataFrame +directions are in one table and can be filtered with ordinary DataFrame operations before being passed on. Both call the same BLAST+ executables with the same parameters, which is why the @@ -137,7 +137,7 @@ instead if `RAVEN_PYTHON_BLASTP` points at them. `getDiamond` and `run_diamond` are drop-in alternatives that search with DIAMOND instead. DIAMOND indexes the database and searches in reduced amino-acid alphabets, which makes it one to two orders of magnitude faster on a full -proteome pair (minutes rather than hours) at the cost of sensitivity for +proteome pair (minutes rather than hours), and less sensitive for distant homologs, where the seeds it uses are less likely to match. For a template within the same genus the difference is small; for a template several hundred million years away, BLASTP finds pairs DIAMOND misses. @@ -266,7 +266,7 @@ strict draft: 32 rxns, 46 genes ::: :::: -Raising the two thresholds costs five reactions and eight genes. Whether that is +Raising the two thresholds removes five reactions and eight genes. Whether that is an improvement depends on what the draft is for: a model that will be curated by hand benefits from the extra candidates, since a wrong reaction is easier to spot than a missing one, while a model used directly for prediction is better diff --git a/docs/guide/index.md b/docs/guide/index.md index e1db79e..c98d149 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -2,14 +2,14 @@ icon: material/folder-open --- -# User guide +# Guide Short, task-focused pages: one job per page, three to eight functions, in **MATLAB and Python side by side**. Start at [Getting started](getting-started.md) and read on, or jump to whichever task you -have in front of you. +are working on. -Two older sets of material sit at the end of this section: a complete +Two older sets of material appear at the end of this section: a complete [reconstruction protocol](../protocol/index.md) for *H. polymorpha*, followed start to finish, and the [legacy tutorials](../tutorials/index.md) from the original RAVEN paper. Both are MATLAB only. @@ -94,8 +94,8 @@ tutorials at the end of this section are MATLAB-only and are not executed. how to condition it on a particular state. 16. [Combining and simplifying models](combining.md), merging models on metabolite names, and taking one apart again. -17. [Comparing models](comparing.md), what changed between two models, and how - much that difference costs. +17. [Comparing models](comparing.md), what changed between two models, and what + effect that difference has. 18. [Reconstruction from homology](homology.md), BLAST a proteome against a template model's genes, and what the cut-offs decide for you. 19. [Reconstruction from KEGG](kegg.md), a draft with no template model at all, @@ -106,7 +106,7 @@ tutorials at the end of this section are MATLAB-only and are not executed. 21. [Table-driven curation](curation.md), applying curation as reviewable tables rather than a script of function calls. 22. [Biomass composition and annotation](biomass.md), what the cell is made - of, rescaling it, and the annotation that outlives the solve. + of, rescaling it, and the annotation that stays useful after the solve. ## Also in this section @@ -123,14 +123,14 @@ not yet at parity between the two toolboxes. ```{toctree} :hidden: -:caption: Install +:caption: Installation ../installation/index ``` ```{toctree} :hidden: -:caption: Functions +:caption: Task pages getting-started model-structure diff --git a/docs/guide/init.md b/docs/guide/init.md index d88c25a..b4a26ea 100644 --- a/docs/guide/init.md +++ b/docs/guide/init.md @@ -22,9 +22,10 @@ ftINIT and nothing else. A tINIT model has to be reproduced in MATLAB. ::: Despite the shared name, the two are **separate implementations that share no -algorithm code**. Reaction scoring and task gap-filling look forked in the -table below only because the two entry points call their shared functions with -different settings, not because two implementations exist: +algorithm code**. Reaction scoring and task gap-filling look like separate +implementations in the table below only because the two entry points call +their shared functions with different settings, not because two +implementations exist: | | tINIT | ftINIT | |---|---|---| @@ -36,7 +37,7 @@ different settings, not because two implementations exist: What they do share is RAVEN's general machinery rather than anything specific to the method: `checkTasks` and `getEssentialRxns` decide which tasks are feasible -and which reactions they need, and beneath that sit `parseTaskList`, +and which reactions they need, and beneath that are `parseTaskList`, `simplifyModel`, the solver layer and the model-manipulation and I/O functions. `scoreModel` is one function for both: `getINITModel` calls it with a single diff --git a/docs/guide/io.md b/docs/guide/io.md index 57f44f3..9e2183f 100644 --- a/docs/guide/io.md +++ b/docs/guide/io.md @@ -17,7 +17,7 @@ directory layout a Git-maintained model repository expects. Which of these you need depends on the file, not on the model: all of them produce the same in-memory model, and none of them is the canonical format. What differs is what survives a round trip and how readable the file is, which -3.2 and 3.4 make concrete. +3.2 and 3.4 show with examples. ## Setup @@ -141,14 +141,14 @@ YAML. ::: :::: -:::{note} Each toolbox is slow in the other's favourite format +:::{note} Each toolbox is fast in one format and slow in the other Reading yeast-GEM takes about **17 s from SBML and 73 s from YAML in Python**, and about **78 s from SBML and 17 s from YAML in MATLAB**, so the ranking is reversed. RAVEN parses YAML itself and goes through libSBML for SBML; cobrapy has the opposite balance. The format therefore follows from what is needed from it, a readable diff or the RAVEN-specific fields YAML preserves, -and a script that spends its time in the reader will often run faster in the -other format. +and a script whose run time is dominated by reading the file will often run +faster in the other format. ::: ## 3.3 Write a model @@ -176,8 +176,8 @@ Document written The two warnings are the prefixing rule in both directions: `exportModel` adds a prefix to a whole field as soon as one id in it starts with something other than a letter or underscore, and `importModel` takes it off again. -Pass `neverPrefix` as `true` to suppress the addition, at the cost of a file -that is not valid SBML. +Pass `neverPrefix` as `true` to suppress the addition, but the resulting file +is not valid SBML. Both `writeYAMLmodel` and `exportModel` take `sortIds`, which sorts a copy before writing and leaves the caller's model untouched. @@ -291,8 +291,8 @@ Document written dependencies.txt, smallYeast.xml, smallYeast.yml ``` -`dir` reports names, so the subdirectories the files sit in are not visible -above: the layout written is `repo/model/yml/smallYeast.yml` and +`dir` reports names, so the subdirectories that contain the files are not +visible above: the layout written is `repo/model/yml/smallYeast.yml` and `repo/model/xml/smallYeast.xml`. Set `subDirs` to `false` to put everything in one folder instead. Identifiers are sorted before writing, with no option to skip it, so successive releases diff cleanly. Left to itself @@ -350,6 +350,6 @@ repositories that pin one. - [Getting started](getting-started.md), what to do with the model once it is loaded. -- [User guide overview](index.md), the other pages and what is planned. +- [Guide overview](index.md), the other pages and what is planned. - [MATLAB vs Python](../raven3-vs-raven-toolbox.md), the full function mapping, including everything that resolves to cobrapy. diff --git a/docs/guide/kegg.md b/docs/guide/kegg.md index 5db2e59..3d2b31b 100644 --- a/docs/guide/kegg.md +++ b/docs/guide/kegg.md @@ -129,7 +129,8 @@ records which of them actually moves the result. ## 19.3 What a KEGG draft is -Genome-scale in size, and unlike a working model in every other respect. +A KEGG draft is genome-scale in size, and unlike a working model in every other +respect. ```text title="the sce draft, measured" reactions: 1357 @@ -155,8 +156,8 @@ in their stoichiometry, which cannot be balanced as written. Turning both off: 1348 rxns, 827 genes (from 1357 and 838) ``` -A change of nine reactions on this organism. The size of the effect depends on -the organism, so measure it rather than assuming it. `keepGeneral` / +That is a change of nine reactions on this organism. The size of the effect +depends on the organism, so measure it rather than assuming it. `keepGeneral` / `keep_general` is off by default for a better reason: general reactions are placeholders like "an alcohol + NAD+", and admitting them produces a network that appears to do far more than it can. diff --git a/docs/guide/media.md b/docs/guide/media.md index 59d95b9..f3e6422 100644 --- a/docs/guide/media.md +++ b/docs/guide/media.md @@ -16,7 +16,7 @@ a condition as reviewable data instead of a paragraph of bound-setting code. ## Setup -`yeast-GEM.xml` from [`docs/data/`](../data/README.md), which ships with an +`yeast-GEM.yml` from [`docs/data/`](../data/README.md), which ships with an aerobic minimal glucose medium already applied. ## 5.1 What is currently open @@ -30,7 +30,7 @@ system. The medium is exactly the set of exchanges with a negative lower bound. :sync: matlab ```matlab -model = importModel('yeast-GEM.xml'); +model = readYAMLmodel('yeast-GEM.yml'); [exchangeRxns, exchangeIdx] = getExchangeRxns(model); fprintf('%d exchange reactions\n', numel(exchangeRxns)); @@ -42,8 +42,6 @@ end ``` ```text -[Warning: The following fields have prefixes removed from all entries. If this is undesired, run importModel with removePrefix as false. Example: importModel('filename.xml',[],false);] -[Warning: The following MIRIAM strings are associated to more than one unique metabolite name: bigg.metabolite/ficytb5 bigg.metabolite/hdd2coa bigg.metabolite/pail_cho bigg.metabolite/pchol_cho bigg.metabolite/succ bigg.metabolite/tchola chebi/CHEBI:138108 chebi/CHEBI:17140 chebi/CHEBI:18097 ...and 23 more] 273 exchange reactions r_1654 ammonium exchange 1000.0 r_1714 D-glucose exchange 1.0 @@ -81,9 +79,9 @@ can secrete as well and is classified `'reverse'`. Selecting on :sync: python ```python -from cobra.io import read_sbml_model +from raven_toolbox.io import read_yaml_model -model = read_sbml_model("yeast-GEM.xml") +model = read_yaml_model("yeast-GEM.yml") shipped = dict(model.medium) # keep it; later steps restore from here print(len(model.exchanges), "exchange reactions") @@ -346,7 +344,7 @@ respiration, and the ratio is the point of the comparison. A medium copied from a paper usually contains more than the model needs. `getMinimalMedium` and cobrapy's `minimal_medium` search for the smallest set of uptakes that still supports a given growth rate, which identifies which component -is doing the work, and catches a nutrient the model can do without because a +is necessary for growth, and catches a nutrient the model does not need because a gap-filled reaction produces it internally. ::::{tab-set} diff --git a/docs/guide/model-structure.md b/docs/guide/model-structure.md index bf8d641..b549a51 100644 --- a/docs/guide/model-structure.md +++ b/docs/guide/model-structure.md @@ -40,7 +40,7 @@ reaction-length field, and the matching column of `model.S`, which is why holds its own links, so `model.remove_reactions([...])` is enough and there is no state left behind to go stale. -That difference also decides where mistakes surface. A RAVEN model can be left in +That difference also decides where mistakes become visible. A RAVEN model can be left in a state no function rejects but later functions misread, which is why RAVEN ships a validator (2.4). A `cobra.Model` cannot reach most of those states at all, because the structure is maintained by the class rather than by the caller. diff --git a/docs/guide/sampling.md b/docs/guide/sampling.md index d836126..d9d75dd 100644 --- a/docs/guide/sampling.md +++ b/docs/guide/sampling.md @@ -151,9 +151,9 @@ generators, so their numbers are not expected to match draw for draw, but they describe the same distribution, and that agreement is the check to make. `FRDS2` is sampled across nearly its whole 1000-unit range, so the loop is not -some rare corner of the space: it is most of it, and most of the draws are spent +some rare corner of the space: it is most of it, and most of the draws land there. Growth is the opposite. Its range runs from 0 to 0.1222, but the samples -sit between about 0.01 and 0.1 and average about 0.05, because near-uniform +fall between about 0.01 and 0.1 and average about 0.05, because near-uniform sampling almost never lands on a vertex and the optimum is a corner with no volume around it. @@ -209,12 +209,12 @@ chrr: 9 dimensions, MVE converged: False, 1 fixed The dimension is a property of the polytope, not of the sampler: it is how many degrees of freedom the network really has once the implicitly-determined reactions are folded out. A model with 53 reactions has far fewer than 53, and -the two toolboxes, which implement CHRR separately, both arrive at **9**. +the two toolboxes, which implement CHRR separately, both compute **9**. `MVE converged: False` is a warning, not a failure. The rounding step stopped before reaching its tolerance, so the last ellipsoid is still a valid rounding and the samples are usable, but on a polytope this elongated mixing is slower -than the defaults assume, and more thinning is the answer if the distribution +than the defaults assume, and more thinning helps if the distribution is uneven. ## 15.4 Sample a state, not a model @@ -310,7 +310,7 @@ which on a genome-scale model skips the expensive part of the run. space is enormous and the distribution says nothing. Constrain first. - **Loops.** They inflate the space being sampled, and every sample drawn inside a cycle is wasted. See [14. Flux variability](fva.md). -- **Genome-scale cost.** Sampling is many LPs per recorded sample. Start with +- **Genome-scale runtime.** Sampling is many LPs per recorded sample. Start with a few hundred samples to see the shape, not tens of thousands. ::: diff --git a/docs/guide/solvers.md b/docs/guide/solvers.md index 4b78dc3..78515e7 100644 --- a/docs/guide/solvers.md +++ b/docs/guide/solvers.md @@ -243,8 +243,8 @@ slim_optimize: nan ``` Check the status before using a number. `slim_optimize` skips building a full -solution, so it is the fast option inside a loop, at the cost of returning -`nan` instead of a reason. +solution, so it is the fast option inside a loop, but it returns `nan` instead +of a reason. ::: :::: diff --git a/docs/guide/tasks.md b/docs/guide/tasks.md index 8365c66..fc163df 100644 --- a/docs/guide/tasks.md +++ b/docs/guide/tasks.md @@ -12,7 +12,7 @@ after cutting a model down. |---|---|---| | `parseTaskList` | `parse_task_list` | read a task-list file | | `checkTasks` | `check_tasks` | run the tasks against a model | -| `checkTasks` (`getEssential`) | `find_task_essential_reactions` | reactions a task cannot do without | +| `checkTasks` (`getEssential`) | `find_task_essential_reactions` | reactions a task requires | | `fitTasks` | `fill_tasks` | add reactions until the tasks pass | ## The file format @@ -51,7 +51,7 @@ a pass. Note what `GROWTH` has to list. Glucose and oxygen in, biomass out, and **CO₂**, because a task closes the model's own exchanges and growth has to put its carbon -somewhere. Leave CO₂ out and the task is infeasible, which reads like a broken +somewhere. Leave CO₂ out and the task is infeasible, which looks like a broken model and is really a broken task. ## 12.1 Read and run the tasks @@ -88,9 +88,9 @@ off `report` gives a structure to test against rather than text to read. Passing the parsed tasks as `taskStructure` makes the second argument, the task file, redundant. `runParallel` evaluates the tasks in parallel -workers, and defaults to `false`, because starting a pool costs more than -it saves on a short task list; on a genome-scale list it is the setting -that matters. +workers, and defaults to `false`, because starting a pool takes longer than +the time it saves on a short task list; on a genome-scale list it is the +setting that matters. ::: :::{tab-item} 🐍 Python :sync: python diff --git a/docs/index.md b/docs/index.md index d4d6c7c..90dd592 100644 --- a/docs/index.md +++ b/docs/index.md @@ -121,7 +121,7 @@ fprintf('Growth rate: %.4f h-1\n', sol.f); ::::{grid} 1 2 2 2 -:::{grid-item-card} User guide +:::{grid-item-card} Guide :link: guide/index :link-type: doc @@ -163,7 +163,7 @@ If you use RAVEN in your research, please cite: > coelicolor*.** *PLoS Computational Biology* 14(10): e1006541. > -See [References](references.md) for the full list, including the earlier +See [Citations](references.md) for the full list, including the earlier RAVEN paper and the GEM reconstruction protocol. ```{toctree} diff --git a/docs/installation/raven.md b/docs/installation/raven.md index d61924a..5370c26 100644 --- a/docs/installation/raven.md +++ b/docs/installation/raven.md @@ -11,9 +11,9 @@ canonical reference is the for. Continuous integration tests R2024b only, so a recent release is the better-covered choice. No additional MathWorks toolboxes required. - A **linear-programming solver**: [Gurobi](https://www.gurobi.com/) (free - academic license, recommended) or **GLPK** (bundled with the - [COBRA Toolbox](https://github.com/opencobra/cobratoolbox)). - See [Choosing a solver](index.md#choosing-a-solver). + academic license, recommended) or **GLPK**, bundled with RAVEN itself, no + separate install needed. See + [Choosing and configuring a solver](#choosing-a-solver-matlab) below. - RAVEN **bundles** `libSBML` and the GLPK mex files for Windows, macOS and Linux. `BLAST+`, `DIAMOND` and `HMMER` are **not** bundled: RAVEN fetches the build for your platform on first use, so the reconstruction functions need @@ -24,6 +24,54 @@ canonical reference is the --- +(choosing-a-solver-matlab)= +## Choosing and configuring a solver + +| Solver | LP | MILP | Relative speed | License | +|---|---|---|---|---| +| GLPK | yes | no | 1x (baseline) | open source, bundled with RAVEN | +| SCIP | yes | yes | 0.33x | open source; bundled on Windows, a separate install on macOS/Linux | +| Gurobi | yes | yes | 4.2x | free academic license | +| COBRA Toolbox | yes | depends on the COBRA solver configured | depends on the COBRA solver configured | depends on the COBRA solver configured | + +MILP-solving functions (`getMinimalMedium`, ftINIT, some gap-filling +algorithms) need a solver that supports MILP; GLPK does not, so those +functions need Gurobi, SCIP, or a MILP-capable solver through the COBRA +Toolbox. + +Set the active solver with `setRavenSolver`, which takes `'gurobi'`, +`'glpk'`, `'soplex'`, or `'cobra'`: + +```matlab +setRavenSolver('gurobi'); +``` + +### Gurobi + +1. Install Gurobi 7.5 or later. +2. Request and download a license (a free academic license covers most + research use). +3. Place the license file where Gurobi's own installer says to. +4. Follow Gurobi's MATLAB integration instructions, then run `savepath` so + MATLAB keeps the change after a restart. +5. `setRavenSolver('gurobi')`. + +### Through the COBRA Toolbox + +RAVEN can solve through whatever solver the COBRA Toolbox has configured, +instead of one of its own bundled options: + +```matlab +changeCobraSolver('glpk'); % or any solver the COBRA Toolbox supports +setRavenSolver('cobra'); +``` + +`ravenCobraWrapper` converts a model between the RAVEN struct and the COBRA +Toolbox structure; see +[RAVEN 3 and raven-toolbox](../raven3-vs-raven-toolbox.md#solvers). + +--- + ## Install ::::{tab-set} @@ -34,6 +82,9 @@ Installs from within MATLAB, with no separate download. 1. Open the **Home** tab and click **Add-Ons → Get Add-Ons**. 2. Search for **RAVEN Toolbox** and click **Add → Add to MATLAB**. 3. [Verify the installation](#verify). + +If MATLAB does not pick up the toolbox after step 2, run +`matlab.addons.enableAddon("RAVEN")` to enable it explicitly. ::: :::{tab-item} {octicon}`download;1em` Release download @@ -59,12 +110,13 @@ Add the folder to the MATLAB path and [verify](#verify). --- -## Verify { #verify } +(verify)= +## Verify From the MATLAB command window: ```matlab -checkInstallation +checkRaven ``` A successful run looks like: @@ -81,9 +133,20 @@ Checking essential binary executables: BLAST+... OK DIAMOND... OK HMMER... OK -*** checkInstallation complete *** +*** checkRaven complete *** ``` +`checkInstallation` still works too: it is the old name, kept as a deprecated +wrapper that forwards to `checkRaven` after a warning. Use `checkRaven` +directly in new work. + +If MATLAB reports that it could not save the path (common on shared or +managed installations where you do not have write access to MATLAB's own +`pathdef.m`), run `addRavenToUserPath` instead: it writes a `startup.m` that +adds RAVEN to the path on every MATLAB start, without touching the shared +path file. `addRavenToUserPath('overwrite', false)` appends to an existing +`startup.m` instead of replacing it. + --- ## Upgrade @@ -92,12 +155,12 @@ Checking essential binary executables: :::{tab-item} {octicon}`plug;1em` Add-Ons manager In MATLAB go to **Help → Check for Updates**, click **Update** for RAVEN, -then run `checkInstallation` again. +then run `checkRaven` again. ::: :::{tab-item} {octicon}`download;1em` Release download Close MATLAB, delete the old RAVEN folder, download and extract the new -release, and run `checkInstallation`. +release, and run `checkRaven`. ::: :::{tab-item} {octicon}`git-branch;1em` Clone with git @@ -105,7 +168,7 @@ release, and run `checkInstallation`. git pull origin main ``` -Then run `checkInstallation`. +Then run `checkRaven`. ::: :::: @@ -116,7 +179,9 @@ Then run `checkInstallation`. ::::{tab-set} :::{tab-item} {octicon}`plug;1em` Add-Ons manager -Go to **Add-Ons → Manage Add-Ons** and remove RAVEN from the list. +Go to **Add-Ons → Manage Add-Ons** and remove RAVEN from the list. Running +`removeRavenFromPath` afterward should report an unrecognized-function error, +confirming RAVEN is off the path. ::: :::{tab-item} {octicon}`download;1em` Release download diff --git a/docs/parameter-tuning/benchmarks.md b/docs/parameter-tuning/benchmarks.md index 38413ae..4d58711 100644 --- a/docs/parameter-tuning/benchmarks.md +++ b/docs/parameter-tuning/benchmarks.md @@ -5,11 +5,11 @@ Everything here was run on 2026-06-20 unless a row says otherwise, on yeast-GEM (4,102 reactions), iJO1366 (2,583) and e_coli_core (95). The parameters that did get a dedicated campaign are in the studies listed -under [Methods](index.md); the current value and one-line reason for every +under [Parameter tuning](index.md); the current value and one-line reason for every parameter on either side is in [Tuned parameter defaults](../tuned-parameters.md). -## Two measurements that ask MATLAB to change +## Two measurements that show MATLAB's default should change ### `fseof`: MATLAB classifies targets with no tolerance at all @@ -51,7 +51,7 @@ which is essential for aerobic growth on glucose: | **`'remove'`** *(Python)* | 94 | **0.000** | GAPD is deleted, glycolysis breaks | Both behaviours are defensible, for different jobs. Keeping the reaction is right -when editing gene annotations, where the network should not change under you. +when editing gene annotations, where the network should not change as a result. Removing it is right for essentiality and engineering work, where a reaction with no enzyme should not carry flux. The defaults disagree about which job is the common one, and the MATLAB default silently produces a false negative in diff --git a/docs/parameter-tuning/index.md b/docs/parameter-tuning/index.md index 6e3a7d4..098fce1 100644 --- a/docs/parameter-tuning/index.md +++ b/docs/parameter-tuning/index.md @@ -2,7 +2,7 @@ icon: material/folder-open --- -# Methods +# Parameter tuning RAVEN, both the MATLAB toolbox and raven-toolbox (Python), ships many functions with numerical defaults: solver tolerances, cut-offs, iteration @@ -24,8 +24,9 @@ trial-and-error, copied from earlier tools, or never reconsidered, and raven-toolbox inherited a mix of ported MATLAB values and upstream (cobrapy) conventions. An existing default in either toolbox is a useful *prior*: it reflects years of practical use, or a well-tested upstream library, but it is -not a gold standard. Where the two implementations differ, the right response -is to run both and measure, not to assume whichever came first is correct. +not necessarily correct. Where the two implementations differ, the right +response is to run both and measure, not to assume whichever came first is +correct. The following criteria apply in rough priority order: @@ -52,9 +53,9 @@ The following criteria apply in rough priority order: 5. **User expectation alignment.** Prefer values that match what a competent user would supply without thinking (e.g. `verbose=True` for a long-running MILP, `sort_ids=False` for round-trip-safe export). -6. **No `None`-surprises.** `None`/empty defaults are fine for optional - features but should never silently change algorithmic behaviour; document - the fallback clearly. +6. **No undocumented `None` behavior.** `None`/empty defaults are fine for + optional features, but any resulting change to algorithmic behaviour must + be documented in the fallback. ### Evaluation workflow per parameter diff --git a/docs/parameter-tuning/studies/ftinit-determinism.md b/docs/parameter-tuning/studies/ftinit-determinism.md index ed7b354..0c1b26c 100644 --- a/docs/parameter-tuning/studies/ftinit-determinism.md +++ b/docs/parameter-tuning/studies/ftinit-determinism.md @@ -112,7 +112,7 @@ Sweeping the value on the first stage (4 seeds) and second stage (3 seeds): | 0.1 | 1 / 1 | −712.87 | all timed out | 1858 s | | 0.05 | 1 / 1 | −712.87 | all timed out | 1948 s | -The headline is not determinism: **the default escalation returns a suboptimal +The main point is not determinism: **the default escalation returns a suboptimal extraction.** It lands 2.0 below the true optimum in stage 1 and 4.0 below in stage 2, 351 kept reactions where the optimum keeps 349, silently, with no warning. diff --git a/docs/parameter-tuning/studies/homology-cutoff-calibration.md b/docs/parameter-tuning/studies/homology-cutoff-calibration.md index 95641fa..0f17ec8 100644 --- a/docs/parameter-tuning/studies/homology-cutoff-calibration.md +++ b/docs/parameter-tuning/studies/homology-cutoff-calibration.md @@ -50,8 +50,8 @@ Scored against KEGG annotations (higher is better): | 50 | 0.882 | 0.736 | 0.640 | 0.323 | Against OMA the best value is 45 for the three fungi and 35 for *E. coli*. So the -two sources put the answer between 35 and 45, and 40 sits comfortably inside -that. Neither supports anything looser. +two sources put the answer between 35 and 45, and 40 falls well inside that +range. Neither supports anything looser. That last point needs stating plainly: counting a missing match as equally bad as a wrong one moves the recommendation to 25, a different answer from the same @@ -80,7 +80,7 @@ identical, so 100 was chosen as the less permissive of the two. | 1e-4 … 1e-50 | 0.923 | 0.804 (identical throughout) | | 1e-100 | 0.877 | 0.703 | -Five orders of magnitude, one answer. Identity and length have already removed +The answer does not change across five orders of magnitude. Identity and length have already removed whatever a looser e-value would have removed, so it has nothing left to decide. Only at 1e-100 does it start discarding good matches. Kept at 1e-30 to match RAVEN. @@ -129,13 +129,13 @@ about 20 minutes per direction. ## What the numbers do not cover -- **KEGG's annotations lean on BLAST comparisons**, so on their own they would +- **KEGG's annotations rely on BLAST comparisons**, so on their own they would partly measure agreement with the method being tested. OMA infers counterparts independently, which is why both were used; they agree. - **The two sources are not directly comparable in absolute terms.** KEGG only covers genes it has annotated (a few hundred well-studied ones per organism) while OMA covers whole proteomes and lists strict counterparts, so ordinary - gene duplicates count against us. Compare the shape of each column, not the + gene duplicates lower the measured score. Compare the shape of each column, not the heights between them. - **The *Y. lipolytica* OMA row is the weakest**: 38% of its OMA pairs could not be matched to KEGG gene names, so that reference is incomplete. @@ -151,12 +151,12 @@ non-model-organism GEMs (hanpo-GEM, rhto-GEM) built by RAVEN's own homology-based reconstruction. It was dropped, for the reason recorded here because it generalises beyond this study. -The diagnostic: walk the thresholds loose one step at a time and ask what +The diagnostic: loosen the thresholds one step at a time and ask what fraction of newly admitted reactions are already in the curated model. The rate held between 0.62 and 0.85 up to hanpo-GEM's actual build settings (`max_evalue=1e-30, min_align_len=150, min_identity=35`) and collapsed to 0.06 -one step past them. That cliff is the reference remembering its own -construction: the curated model agrees with predictions made at *its own* build +one step past them. That sharp drop reflects the reference matching its own +original build settings: the curated model agrees with predictions made at *its own* build settings and disagrees with everything else, regardless of whether those other settings are better or worse. Optimising against it returns the build settings whether or not they are good; it cannot measure correctness, only diff --git a/docs/parameter-tuning/studies/init-param-calibration.md b/docs/parameter-tuning/studies/init-param-calibration.md index 99d8b72..0ab50e4 100644 --- a/docs/parameter-tuning/studies/init-param-calibration.md +++ b/docs/parameter-tuning/studies/init-param-calibration.md @@ -118,7 +118,7 @@ doesn't dominate); a 1% gap is ~30% faster with ~3% reaction-set drift. Each `eps` value gives a slightly different model (Jaccard ~0.95 across the range); the reaction-set spread is ~5%. `eps=1.0` is RAVEN's default; smaller values produce *slightly* -larger models (loosen the connectivity bar). Pick by what the data justifies; see the +larger models (loosen the connectivity threshold). Pick by what the data justifies; see the caveat at the top of `init.py`. **prod_weight** (gap=0.005, the metabolite-production reward, *changes the model*): @@ -190,8 +190,8 @@ Lowering `eps` (1.0 → 0.1) does **not** fix it; the issue is that 100+ reactio simultaneously each carry a fixed positive flux in their forced direction at steady state. ftINIT avoids this by using an *adaptive* per-reaction forcing magnitude (`min(0.99·|previous flux|, force_on)`) so each essential is forced at a value it -*actually carried* in a prior feasible solution. tINIT's one-size-fits-all `eps` -mechanism doesn't have that escape hatch. +*actually carried* in a prior feasible solution. tINIT's `eps` mechanism applies +one fixed value to every reaction and has no equivalent way to avoid this problem. **Practical takeaway.** For functional context-specific models on genome-scale data, use ftINIT, the task layer (gap-fill, adaptive essential forcing) is what makes the pipeline @@ -223,7 +223,7 @@ The metabolic-task + gap-fill layer is held fixed; only the expression input is **Findings:** -* **Robust to noise, sensitive to sparsity.** Multiplicative expression noise barely changes +* **The model is robust to noise but sensitive to sparsity.** Multiplicative expression noise barely changes the model (Jaccard 0.92–0.95, size stable, all tasks pass). Sparsity is far more damaging: 50% dropout already drops the reaction set to **0.71 Jaccard** (and shrinks 7777→5968), 70% to **0.59**. @@ -275,7 +275,7 @@ restores fidelity lost to dropout; that is a property of the data, not the pipel For the reasons in §1.5, tINIT cannot accept the full task-essential set as forced reactions; this section runs `get_init_model` with `essential_rxns=[]` to show the realistic tINIT behaviour on the same degradation gradient, i.e. the *cost of not -having ftINIT's gap-fill safety net*. +having ftINIT's gap-fill mechanism*. | input | n_rxns | tasks pass | frac | Jaccard vs clean | |-------|-------:|-----------:|-----:|-----------------:| @@ -287,7 +287,7 @@ having ftINIT's gap-fill safety net*. | downsample 50% | 5006 | 24/69 | 0.348 | 0.722 | | downsample 70% | 3541 | 19/69 | 0.275 | 0.515 | -**The headline contrast with ftINIT:** +**The main contrast with ftINIT:** | | ftINIT (task layer) | tINIT (no task layer) | |---|---|---| @@ -323,7 +323,7 @@ Same conclusion as the ftINIT levers: parameter tuning can nudge (`prod_weight or a larger `eps` modestly grows the model and lifts Jaccard from 0.41 to ~0.48), but **no tINIT parameter recovers anything close to ftINIT's functionality** (22/69 at best vs ftINIT's 67–69/69 at the same dropout). The gap-fill layer, not the parameter -choice, is what bridges the gap. +choice, is what makes up the difference. --- @@ -350,7 +350,7 @@ nothing to reconcile, but the values rest on convention rather than evidence. See [init-solver-benchmark.md](init-solver-benchmark.md) for the genome-scale solver comparison (Gurobi/HiGHS/GLPK) and [tests/test_init_solvers.py](https://github.com/SysBioChalmers/raven-toolbox/blob/develop/tests/test_init_solvers.py) -for CI parameterised over installed MILP backends. Headline: at genome scale only Gurobi +for CI parameterised over installed MILP backends. Summary: at genome scale only Gurobi is viable today; HiGHS fails on an upstream optlang `hybrid_interface.clone()` bug; GLPK ignores `configuration.timeout` on MIP and ran 1 h+ without converging. Toy-scale correctness is portable (Gurobi + GLPK give identical verdicts on the unit-test diff --git a/docs/parameter-tuning/studies/kegg-hmm-cutoff-calibration.md b/docs/parameter-tuning/studies/kegg-hmm-cutoff-calibration.md index 651146b..10c2e65 100644 --- a/docs/parameter-tuning/studies/kegg-hmm-cutoff-calibration.md +++ b/docs/parameter-tuning/studies/kegg-hmm-cutoff-calibration.md @@ -124,7 +124,7 @@ recall / F1 and reaction recovery vs the annotation. | 1e-100 | 0.87 | 0.50 | 0.64 | 0.47 | 21 | **Reading:** recall is flat-and-high from 1e-10 to ~1e-30, then falls as the -cut-off eats into the matched tail, gently for model organisms, sharply for the +cut-off removes part of the matched tail, gently for model organisms, sharply for the divergent `mge` (rxn recall 0.98 → 0.87 from 1e-30 → 1e-50, → 0.47 at 1e-100). The recall lost to a stricter cut-off is *not* noise rejection (noise is at 1e-8); it is real annotation. `rxn_novel` shrinks with stricter cut-offs because strong diff --git a/docs/parameter-tuning/studies/sampling-convergence-calibration.md b/docs/parameter-tuning/studies/sampling-convergence-calibration.md index 309536e..9e5e8cb 100644 --- a/docs/parameter-tuning/studies/sampling-convergence-calibration.md +++ b/docs/parameter-tuning/studies/sampling-convergence-calibration.md @@ -17,7 +17,7 @@ compute for independence. On yeast-GEM (`n_samples=300`, `warmup=1000`, Gurobi): Even at 500, consecutive samples remain 85% correlated. The decay is too slow to fix by raising the setting: a fivefold increase from 20 to 100 removes 0.047 of the autocorrelation, and the next fivefold removes 0.077. Reaching roughly -0.3 (a common rule of thumb for near-independence) would need thinning in the tens of +0.3 (a commonly used approximate threshold for near-independence) would need thinning in the tens of thousands, which is weeks of compute for 1000 samples. Treating an AR(1) process, effective sample size is `n × (1−ρ) / (1+ρ)`. At the @@ -76,8 +76,8 @@ Worst-converged reactions: **Already informative at this scale.** Even on a 95-reaction textbook model, one reaction (`EX_succ_e`, succinate exchange, a byproduct/overflow route) -clears the "not converged" threshold (R-hat 1.30) at the default settings, and -nearly half the reactions fail the stricter 1.01 bar. This is a genuinely +exceeds the "not converged" threshold (R-hat 1.30) at the default settings, and +nearly half the reactions fail the stricter 1.01 threshold. This is a genuinely different failure mode from what the single-chain ESS result showed: it's not that samples are autocorrelated *within* a chain, it's that independent chains land on measurably different distributions for a subset of reactions, @@ -129,7 +129,7 @@ warning (increase `thinning`/`n_samples`, check ESS, or switch to problem; this justifies raising it from an FYI-level note to an explicit warning with numbers attached. -## Does `method='chrr'` fix it? Yes on e_coli_core, but at a cost that may not scale +## Does `method='chrr'` fix it? Yes on e_coli_core, but it comes at a cost that may not scale Same 4 chains × 300 samples on e_coli_core, `method='chrr'` instead of `'achr'`: @@ -213,10 +213,10 @@ ratio. (Contrast e_coli_core, where 300 samples/chain gave stable, well-behaved R-hat throughout.) This run cannot distinguish "CHRR doesn't work at genome scale" from "R-hat needs more than 20 samples to mean anything"; telling those apart would need a genome-scale CHRR run with -enough samples for a stable R-hat, which circles back to the cost problem +enough samples for a stable R-hat, which has the same cost problem described above. -## Bottom line +## Summary - **Default settings are unconverged for most reactions at genome scale**: robust finding, confirmed by two independent lines of evidence (ESS and @@ -239,7 +239,7 @@ above. ## Two other sampling settings that were measured -Both diverge from MATLAB, and in both cases the divergence is the point. +Both diverge from MATLAB, and in both cases the divergence is deliberate. `replace_max_bound` swaps big-M upper bounds for infinity before sampling, and applies only to `method='random_objective'`. RAVEN-convention models use 1000 as diff --git a/docs/protocol/anticipated-results.md b/docs/protocol/anticipated-results.md index 2c60670..92c99fb 100644 --- a/docs/protocol/anticipated-results.md +++ b/docs/protocol/anticipated-results.md @@ -13,7 +13,7 @@ Following this protocol yields a **draft** genome-scale metabolic model for The published hanpo-GEM (the curated result distributed in the repository) contains on the order of **2,370 reactions, 2,118 metabolites and 984 genes**, -your draft will be in the same ballpark but is expected to differ, since it is a +your draft will be similar in size but is expected to differ, since it is a starting point for the open-ended process of manual curation. ## What "done" looks like diff --git a/docs/protocol/index.md b/docs/protocol/index.md index 6212614..3ac43ff 100644 --- a/docs/protocol/index.md +++ b/docs/protocol/index.md @@ -5,8 +5,9 @@ icon: material/folder-open # Worked protocol: *Hansenula polymorpha* A complete homology-based reconstruction of `hanpo-GEM`, followed from start to -finish: template models in, a growing methylotrophic draft out. This is the -published pipeline, in order, with the judgement calls left visible. +finish: it takes template models as input and produces a growing methylotrophic +draft. This is the published pipeline, in order, with the judgement calls left +visible. It is the counterpart to the [user guide](../guide/index.md). The numbered guide pages answer "how do I do this one thing"; this protocol answers "what does a diff --git a/docs/raven3-migration.md b/docs/raven3-migration.md index 736ed4a..9ed1842 100644 --- a/docs/raven3-migration.md +++ b/docs/raven3-migration.md @@ -30,8 +30,8 @@ dependencies were dropped, and the calling convention for optional function arguments changed almost everywhere. None of this was accidental; see the project's [v3 development review](https://github.com/SysBioChalmers/RAVEN/blob/develop3/docs/v3_review.md) for the rationale, but it means that **most non-trivial RAVEN 2 scripts need to -be checked**, even if most of the core reconstruction/analysis behavior is -unchanged in spirit. +be checked**, even though the core reconstruction and analysis behavior is +mostly the same. :::{note} This is the MATLAB-to-MATLAB axis This page is about RAVEN 2 → RAVEN 3, both MATLAB. How the Python package @@ -40,8 +40,9 @@ differs from the MATLAB one is a separate question, answered in ::: Start with the [upgrade checklist](#upgrade-checklist) below, then read -[Backward-incompatible changes](#backward-incompatible-changes); it is the -punch list. The sections after it go into the detail behind each item. +[Backward-incompatible changes](#backward-incompatible-changes); it lists +everything that can break. The sections after it go into the detail behind +each item. --- @@ -113,7 +114,8 @@ reconstruction), `pathway/` and `plotting/` (visualization), `legacy/` (CellDesigner import and other pre-2.0 code), `struct_conversion/`'s Excel-POI helpers. -**Practical impact is smaller than it looks.** If your scripts call RAVEN +**The reorganization affects fewer scripts than the change list suggests.** +If your scripts call RAVEN functions by name (the normal usage pattern, with the whole RAVEN folder tree, including subfolders, added to the MATLAB path via `addRavenToUserPath` or `addpath(genpath(...))`), moving a file to a new subfolder does not break the @@ -126,8 +128,8 @@ name with your own; folder names are irrelevant otherwise. The full moved-file mapping (RAVEN 2 path → RAVEN 3 path) for every relocated function is available on request / in the repository's git history (`git diff --stat -M develop...develop3`); it is not reproduced in full here -because it is large and, per the point above, rarely something you need to act -on. +because it is large and, as the point above explains, rarely something you +need to act on. --- @@ -154,7 +156,7 @@ parameter name. Everything before that point is assigned positionally, in the order the function's `parseRAVENargs` specification declares; everything from that point on must be valid name-value pairs. -**This means old positional calls keep working, *provided* the function's new +**This means old positional calls keep working, if the function's new parameter order still matches the old positional order.** In every function spot-checked for this guide (`importModel`, `exportModel`, `exportToExcelFormat`, `removeReactions`, `ftINIT`, `fillGaps`, `fitTasks`, @@ -260,8 +262,8 @@ an air-gapped install, and the full dependency comparison. ## 4. Removed functionality Beyond the items already listed as backward-incompatible above, RAVEN 3 removed -a number of functions and whole subsystems as part of a deliberate "leaner -codebase" push. None of these have call sites left in RAVEN 3 itself. +a number of functions and whole subsystems as part of a deliberate effort to +make the codebase smaller. None of these have call sites left in RAVEN 3 itself. | Removed | What it did | Replacement / notes | |---|---|---| @@ -493,7 +495,7 @@ functions, except where noted. | Installation self-check | `installation/checkInstallation.m`; ran the full test suite to populate its pass/fail table | renamed `checkRaven`, moved to the repo root; does fast, targeted checks (a small import/export round-trip, a trivial LP per solver) instead of invoking the full test classes, and proactively offers to download missing binaries | Net effect: a bare RAVEN 3 clone is far smaller and installs with fewer MATLAB -toolbox prerequisites, at the cost of needing network access the first time +toolbox prerequisites. The trade-off: it needs network access the first time KEGG- or homology-based reconstruction functions actually run. --- diff --git a/docs/raven3-vs-raven-toolbox.md b/docs/raven3-vs-raven-toolbox.md index e852049..419b305 100644 --- a/docs/raven3-vs-raven-toolbox.md +++ b/docs/raven3-vs-raven-toolbox.md @@ -8,9 +8,9 @@ RAVEN exists as two independent implementations: [cobrapy](https://cobrapy.readthedocs.io/), so a model is a `cobra.Model` and the wider Python ecosystem works on it directly. -They cover the same ground (homology and KEGG reconstruction, metabolic tasks, +They do the same things (homology and KEGG reconstruction, metabolic tasks, gap-filling, context-specific extraction with ftINIT, compartment assignment, -model comparison), but they are **not transliterations of each other**. Names +model comparison), but one is not a direct translation of the other. Names differ, some capabilities exist on one side only, and a handful of functions answer the same question differently. @@ -20,8 +20,8 @@ build time. ## Which one should you use? -Neither is a reduced version of the other, so the choice is usually made by -what surrounds the model rather than by the toolbox itself. +Neither is a reduced version of the other, so the right choice usually depends +on the rest of your code, not on the toolbox itself. **Use raven-toolbox** if the surrounding code is Python, if you want the model to be a `cobra.Model` that every cobrapy tool accepts without conversion, if @@ -36,10 +36,10 @@ Toolbox structure. function, the mapping table names the pair; where only one does, the sections below say which and why. -## Names do not convert mechanically +## Changing the case does not give the matching name -MATLAB uses `camelCase`, Python `snake_case`, but rewriting the case is the -most common way to arrive at a name that does not exist. Much of the API was +MATLAB uses `camelCase` and Python uses `snake_case`, but changing only the +case usually produces a name that does not exist. Much of the API was deliberately renamed as it was ported: | MATLAB | Python | @@ -134,9 +134,8 @@ added only once the difference has been confirmed in both sources. :::{admonition} Not a complete list :class: info -Absence from this section is not a guarantee of identical behaviour. Where -an exact answer matters (reproducing a published result, comparing two -pipelines); see [what "identical results" means](#what-identical-results-means). +Absence from this section is not a guarantee of identical behaviour. It only +means the difference has not been confirmed and written up yet. ::: ### Duplicate reactions: gene associations are not merged @@ -154,7 +153,7 @@ not. If you are contracting a draft assembled from several templates, where the same reaction commonly arrives with different gene associations, check the GPRs of the survivors afterwards. -### Metabolic tasks: same verdicts, very different cost +### Metabolic tasks: the same result, a different runtime `checkTasks` rebuilds the working model from the original for each task. `check_tasks` instead applies each task's constraints to one model inside a @@ -162,14 +161,15 @@ of the survivors afterwards. of edit cobra's context manager does not track (direct mass-balance bound changes). -The pass/fail verdicts are the same. The cost is not: at genome scale the copy -dominates the MATLAB runtime, which is why the Python version reuses a single -model. This affects runtime comparisons, not results. +The pass and fail results are the same. The runtime is not: at genome scale, +copying the model for each task dominates the MATLAB runtime, which is why the +Python version reuses a single model. This changes runtime comparisons, not +results. -### Gap-filling: one function becomes three +### Gap-filling: `fillGaps` splits into three functions in raven-toolbox -`fillGaps` covers several jobs behind one interface. raven-toolbox splits them, -so porting a `fillGaps` call means choosing: +`fillGaps` does several different jobs through one function call. +raven-toolbox splits them, so porting a `fillGaps` call means choosing: | What you were doing | Use | |---|---| @@ -178,8 +178,9 @@ so porting a `fillGaps` call means choosing: | MILP filling with explicit weights | `fill_gaps_kumar_milp` | | Only *finding* the gaps (`canExchange`, `checkProduction`, `getAllSubGraphs`, `haveFlux`) | `analyse_topology` | -The choice changes both the reaction set added and the runtime; they are -different algorithms, not one algorithm behind three names. +The choice changes both the reaction set added and the runtime, because each +of the three functions uses a different algorithm; they are not the same +algorithm under three different names. ### Anything solved by MILP @@ -189,72 +190,26 @@ value**. Two runs can return different reaction sets and both be correct; across languages, across solvers, and in some configurations across runs of the same solver. -Do not compare these outputs for identity. Compare them for overlap, and expect -a band rather than a number. +Do not compare these outputs for identity. Compare them for overlap, and +expect a range of acceptable values, not one exact number. -### A note on elemental balance +### Elemental balance: an unknown result is not the same as balanced -Both `getElementalBalance` and `get_elemental_balance` grade each reaction rather -than returning a bare balanced/unbalanced flag: a reaction whose metabolites lack -formulas is reported as *unknown*, not as balanced. The two agree. +Elemental balance checks whether a reaction has the same count of each +chemical element (carbon, hydrogen, oxygen, and so on) on both sides, the way +a correct chemical equation must. `getElementalBalance` and +`get_elemental_balance` each report one of three results per reaction, not +two: `balanced`, `unbalanced`, or `unknown`. A reaction is `unknown` when one +of its metabolites has no chemical formula recorded, so the element counts +cannot be computed at all; that is different from `unbalanced`, which means +the counts were computed and did not match. The two functions agree on this +three-way result. -The distinction matters when moving to plain cobrapy, whose `check_mass_balance` -does not make it, which is the reason raven-toolbox keeps its own function -instead of delegating. - -## What "identical results" means - -When two implementations of the same method exist, the question is whether they -give the same answer. That depends on which function you -mean, because "the same" is achievable for some and meaningless for others. - -### Exact - -The output can and should match value for value. Anything deterministic that -transforms a model or a file rather than solving an optimisation problem: - -- model I/O: SBML and YAML round-trips, Excel export -- task-list parsing -- gene-association normalisation (`grRuleToDNF` / `gpr_to_dnf`) -- elemental balance -- identifier sorting, model merging, reversibility splitting, GPR expansion -- KEGG table parsing and homology ortholog assignment - -If these disagree, one of them is wrong. - -### Set-level - -The output is the solution to a mixed-integer problem that has many optima of -equal value, so identity is not a meaningful target; a different reaction set of -the same objective value is not an error. This covers ftINIT extraction, -gap-filling, and compartment assignment. - -The meaningful comparison is overlap: how similar are the two models, expressed -as a Jaccard index or a containment fraction, against a recorded baseline. Two -extractions agreeing to a Jaccard of 0.97 on a genome-scale model is a strong -result, not a near-miss. - -Alternate optima also mean the *solver* matters. The same code with Gurobi and -with GLPK can land on different optima, so a cross-language comparison should -hold the solver fixed before concluding anything about the languages. - -### Statistical - -Flux sampling and random sampling explore a space rather than compute a point. -Two runs of the *same* implementation differ. Compare distributions (means, -marginals, coverage) at a fixed seed, never individual samples. - -### What is actually verified today - -raven-toolbox has been validated against MATLAB RAVEN on Human-GEM (five -Hart2015 cell-line models, Jaccard 0.975–0.980), on yeast, and on a -multi-organism set. Those are set-level comparisons of the extraction pipeline, -reported in the raven-toolbox repository. - -They are, at present, **reported** rather than **enforced**: no test fails if the -two implementations drift apart. Building that harness (committed fixtures, a -MATLAB driver that records the reference output, and tiered assertions matching -the three levels above) is planned work; this page cannot yet point at it. +That third case is lost if you switch to plain cobrapy: its +`check_mass_balance` has no separate `unknown` result, so a reaction with a +missing formula and a reaction that is genuinely unbalanced can look the +same. raven-toolbox keeps its own function instead of using cobrapy's +directly, specifically to keep that distinction. ## Solvers @@ -262,7 +217,7 @@ the three levels above) is planned work; this page cannot yet point at it. |---|---|---| | Configuration | `setRavenSolver('gurobi')` | `cobra.Configuration().solver = 'gurobi'` | | Recommended solver | Gurobi (free academic licence) | Gurobi (free academic licence) | -| Open-source option | GLPK (via COBRA Toolbox) | GLPK (bundled with cobrapy) | +| Open-source option | GLPK (bundled with RAVEN) | GLPK (bundled with cobrapy) | Genome-scale MILP work (ftINIT extraction in particular) is where the choice matters most; see [Installation](installation/index.md) for the full solver @@ -281,8 +236,8 @@ and RAVEN's `importExcelModel` was removed in the RAVEN 3 refactor. ## Coming from RAVEN 2.0 to Python -raven-toolbox is not a port of RAVEN 2.0; it is a fresh implementation that -made different architectural choices where RAVEN 2.0 showed its age. If you are +raven-toolbox is not a port of RAVEN 2.0; it is a new implementation that +made different design choices where RAVEN 2.0's design had become outdated. If you are moving a RAVEN 2.0 workflow straight to Python rather than to RAVEN 3, three differences matter beyond everything above. @@ -301,8 +256,8 @@ straightforward. Every public function carries type annotations and passes folder, and raven-toolbox never had it. The reason is not neglect: MetaCyc provides a single representative sequence per enzyme, which gives intrinsically low gene-calling precision, measured at roughly two-thirds of reaction -assignments wrong at the default cutoff, with no cutoff that rescues it. Use the -KEGG or homology routes. +assignments wrong at the default cutoff, with no cutoff value that fixes the +problem. Use the KEGG or homology routes. What stayed the same are the algorithms: homology search, gap-filling and KEGG reconstruction follow the same published methods, and models diff --git a/docs/references.md b/docs/references.md index 11c0a1b..fca8446 100644 --- a/docs/references.md +++ b/docs/references.md @@ -1,4 +1,4 @@ -# References +# Citations ## RAVEN diff --git a/docs/tuned-parameters.md b/docs/tuned-parameters.md index 61dd4ce..2513647 100644 --- a/docs/tuned-parameters.md +++ b/docs/tuned-parameters.md @@ -208,7 +208,7 @@ RAVEN MATLAB: `checkTasks`. raven-toolbox: `check_tasks`, `find_task_essential_r ## Cross-toolbox parity decisions Policy: where Python and MATLAB RAVEN disagree on a default, pick one value for -both rather than let them drift, except where the divergence is forced by a real +both rather than let them diverge, except where the divergence is forced by a real implementation difference (different solver stack, different algorithm, different data schema), in which case forcing identical values would change correct behaviour into incorrect behaviour. Every row below either says which side has to diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md index 110fe79..8e503c7 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.md @@ -34,11 +34,12 @@ folder of the RAVEN repository. the completed exercise. :::{tip} Python users -The reconstruction concepts carry over directly to raven-toolbox, but the -function names are not always a mechanical `snake_case` rewrite; some RAVEN -functions map to cobrapy instead (`solveLP` → `model.optimize()`), and some -have no Python counterpart at all (there is no Excel reader). Look each one up -in the [API reference](../api/index.md), and see +The reconstruction concepts carry over directly to raven-toolbox, but +converting the name to `snake_case` does not always give the matching +raven-toolbox function name; some RAVEN functions map to cobrapy instead +(`solveLP` → `model.optimize()`), and some have no Python counterpart at all +(there is no Excel reader). Look each one up in the +[API reference](../api/index.md), and see [RAVEN 3 and raven-toolbox](../raven3-vs-raven-toolbox.md) for what maps where. ::: diff --git a/docs/tutorials/tutorial1.md b/docs/tutorials/tutorial1.md index e03b4b3..26b28ef 100644 --- a/docs/tutorials/tutorial1.md +++ b/docs/tutorials/tutorial1.md @@ -110,9 +110,9 @@ The printed table is capped at 20 rows, but `res.changed` holds every changed reaction and `res.turnedOn` / `res.turnedOff` / `res.flipped` list those that switched state. -By drilling down this way you can understand the flux redistributions that give -rise to different phenotypes; for example, on glucose ATP is generated in -glycolysis, whereas on ethanol it involves acetate. +Comparing the fluxes this way shows the flux redistributions that produce +different phenotypes; for example, on glucose ATP is generated in glycolysis, +whereas on ethanol it involves acetate. ## Full script diff --git a/docs/tutorials/tutorial4.md b/docs/tutorials/tutorial4.md index bae39f0..8747268 100644 --- a/docs/tutorials/tutorial4.md +++ b/docs/tutorials/tutorial4.md @@ -1,7 +1,7 @@ # Tutorial 4: Fix an erroneous model -The power of GEMs comes from their size, but that size makes errors almost -inevitable, whether you build a model yourself or use someone else's. This +GEMs are powerful because of their size, but that size also makes errors +almost inevitable, whether you build a model yourself or use someone else's. This exercise is a systematic round of quality control on a deliberately broken version of the small yeast model, `smallYeastBad.yml`. diff --git a/scripts/gen_api_pages_sphinx.py b/scripts/gen_api_pages_sphinx.py index 743a188..6400b66 100644 --- a/scripts/gen_api_pages_sphinx.py +++ b/scripts/gen_api_pages_sphinx.py @@ -271,47 +271,57 @@ def generate(docs_root: Path) -> None: listed = "\n - ".join(unresolved) raise SystemExit(f"gen_api_pages_sphinx: scripts/curated_pairs.yml is out of date:\n - {listed}") - pairs: list[tuple[str, str, str, str, str, bool]] = [] + cobrapy_docs_url = "https://cobrapy.readthedocs.io/en/latest/autoapi/cobra/index.html" + + # Each row: (matlab name, matlab folder, python-column markdown, summary text). + rows: list[tuple[str, str, str, str]] = [] seen_matlab: set[str] = set() + n_auto = 0 for folder, _title in MATLAB_CATEGORIES: for f in matlab.get(folder, []): match = py_by_norm.get(norm(f["name"])) if match: - pairs.append((f["name"], folder, match["name"], match["package"], f["summary"] or match["summary"], False)) + p_cell = f"[`{match['name']}`](api/python/{match['package']}.md#{slug(match['name'])})" + rows.append((f["name"], folder, p_cell, f["summary"] or match["summary"])) seen_matlab.add(f["name"]) + n_auto += 1 + n_curated = 0 for m_name, p_name in curated["aliases"].items(): if m_name in seen_matlab: continue folder = matlab_all[m_name] obj = py_by_name[p_name] m_summary = next((f["summary"] for f in matlab.get(folder, []) if f["name"] == m_name), "") - pairs.append((m_name, folder, p_name, obj["package"], m_summary or obj["summary"], True)) + p_cell = f"[`{p_name}`](api/python/{obj['package']}.md#{slug(p_name)})" + rows.append((m_name, folder, p_cell, m_summary or obj["summary"])) + seen_matlab.add(m_name) + n_curated += 1 + n_cobrapy = 0 + for m_name, target in curated["cobrapy"].items(): + folder = matlab_all[m_name] + m_summary = next((f["summary"] for f in matlab.get(folder, []) if f["name"] == m_name), "") + p_cell = f"`{target}` {{bdg-link-secondary}}`cobrapy <{cobrapy_docs_url}>`" + rows.append((m_name, folder, p_cell, m_summary)) + seen_matlab.add(m_name) + n_cobrapy += 1 - n_auto = sum(1 for r in pairs if not r[5]) lines = [ "# MATLAB vs Python", "", "RAVEN ships as a MATLAB toolbox and as the Python package **raven-toolbox**. " "This page is generated from the source of both toolboxes at build time. " - "Pairs are found automatically where the names match, and completed from a " - "curated list where they do not; every name is verified to exist.", + "Pairs are found automatically where the names match, completed from a " + "curated list where they do not, and marked with a " + f"{{bdg-link-secondary}}`cobrapy <{cobrapy_docs_url}>` badge where cobrapy " + "covers the function instead of raven-toolbox. Every name is verified to exist.", "", "## Paired functions", "", - f"**{len(pairs)}** pairs, {n_auto} matched automatically, {len(pairs) - n_auto} curated.", + f"**{len(rows)}** RAVEN functions listed: {n_auto} matched automatically, " + f"{n_curated} from a curated list, {n_cobrapy} covered by cobrapy instead of " + "raven-toolbox.", "", "| RAVEN (MATLAB) | raven-toolbox (Python) | Summary |", "|---|---|---|", ] - for m_name, m_folder, p_name, p_pkg, text, _curated in sorted(pairs, key=lambda r: r[0].lower()): + for m_name, m_folder, p_cell, text in sorted(rows, key=lambda r: r[0].lower()): m_link = f"[`{m_name}`](api/matlab/{m_folder}.md#{slug(m_name)})" - p_link = f"[`{p_name}`](api/python/{p_pkg}.md#{slug(p_name)})" - lines.append(f"| {m_link} | {p_link} | {cell(text)} |") - - lines += ["", "## Covered by cobrapy", "", - "These RAVEN functions have no raven-toolbox counterpart because cobrapy " - "already provides the capability.", "", - "| RAVEN (MATLAB) | Use instead |", "|---|---|"] - for m_name, target in sorted(curated["cobrapy"].items(), key=lambda kv: kv[0].lower()): - folder = matlab_all[m_name] - m_link = f"[`{m_name}`](api/matlab/{folder}.md#{slug(m_name)})" - url = "https://cobrapy.readthedocs.io/en/latest/autoapi/cobra/index.html" - lines.append(f"| {m_link} | [`{target}`]({url}) |") + lines.append(f"| {m_link} | {p_cell} | {cell(text)} |") lines += ["", "## Deliberately not ported", "", "| RAVEN (MATLAB) | Why not |", "|---|---|"] for m_name, reason in sorted(curated["not_ported"].items(), key=lambda kv: kv[0].lower()): @@ -319,7 +329,7 @@ def generate(docs_root: Path) -> None: m_link = f"[`{m_name}`](api/matlab/{folder}.md#{slug(m_name)})" lines.append(f"| {m_link} | {cell(reason)} |") - accounted = {r[0] for r in pairs} | set(curated["cobrapy"]) | set(curated["not_ported"]) + accounted = {r[0] for r in rows} | set(curated["not_ported"]) unmapped = sorted((n for n in matlab_all if n not in accounted), key=str.lower) if unmapped: lines += ["", "## Not yet mapped", "", From 4bbaa57327f8b237b49beeb0225188c9d5f038f5 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Wed, 9 Sep 2026 18:38:37 +0200 Subject: [PATCH 3/4] Make every cobrapy badge a real link to the cobrapy docs guide/index.md's own admonition already claimed the badge links to the cobrapy documentation, but the plain {bdg-secondary} role used across all 14 guide pages has no href; only the new matlab-vs-python.md badge did. --- docs/guide/biomass.md | 2 +- docs/guide/building.md | 8 ++++---- docs/guide/deletions.md | 6 +++--- docs/guide/editing.md | 4 ++-- docs/guide/fba.md | 10 +++++----- docs/guide/fva.md | 10 +++++----- docs/guide/getting-started.md | 10 +++++----- docs/guide/index.md | 2 +- docs/guide/io.md | 4 ++-- docs/guide/media.md | 6 +++--- docs/guide/model-structure.md | 2 +- docs/guide/quality-control.md | 4 ++-- docs/guide/sampling.md | 2 +- docs/guide/solvers.md | 8 ++++---- 14 files changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/guide/biomass.md b/docs/guide/biomass.md index 3dbd1f6..732672e 100644 --- a/docs/guide/biomass.md +++ b/docs/guide/biomass.md @@ -14,7 +14,7 @@ annotation that makes a model interpretable to something other than a solver. | `scaleBiomassPseudoreaction` | `rescale_pseudoreaction` | rescale a pseudoreaction and rebalance it | | `assignSBOterms` | `add_sbo_terms` | label reactions and metabolites with SBO terms | | `loadDeltaGCSV`, `saveDeltaGCSV` | `load_delta_g_csv`, `save_delta_g_csv` | thermodynamic data through CSV | -| `extractMiriam`, `editMiriam` | `Object.annotation` {bdg-secondary}`cobrapy` | read and edit database cross-references | +| `extractMiriam`, `editMiriam` | `Object.annotation` {bdg-link-secondary}`cobrapy ` | read and edit database cross-references | ## Setup diff --git a/docs/guide/building.md b/docs/guide/building.md index 5673f86..915e8da 100644 --- a/docs/guide/building.md +++ b/docs/guide/building.md @@ -9,11 +9,11 @@ reconstruction is involved. | MATLAB | Python | | |---|---|---| -| `addMets` | `Metabolite` {bdg-secondary}`cobrapy` | add metabolites | +| `addMets` | `Metabolite` {bdg-link-secondary}`cobrapy ` | add metabolites | | `addRxns` | `add_reactions_from_equations` | add reactions from equation strings | -| `addGenesRaven` | auto-created from the GPR {bdg-secondary}`cobrapy` | add genes | -| `addExchangeRxns` | `Model.add_boundary` {bdg-secondary}`cobrapy` | add exchange reactions | -| `constructEquations` | `Reaction.reaction` {bdg-secondary}`cobrapy` | read the equations back | +| `addGenesRaven` | auto-created from the GPR {bdg-link-secondary}`cobrapy ` | add genes | +| `addExchangeRxns` | `Model.add_boundary` {bdg-link-secondary}`cobrapy ` | add exchange reactions | +| `constructEquations` | `Reaction.reaction` {bdg-link-secondary}`cobrapy ` | read the equations back | The important part is the same in both: **write the reaction as an equation string** and let the toolbox derive the stoichiometry, rather than filling in a diff --git a/docs/guide/deletions.md b/docs/guide/deletions.md index b3e421f..d35c445 100644 --- a/docs/guide/deletions.md +++ b/docs/guide/deletions.md @@ -9,11 +9,11 @@ distribution better than plain FBA does". | MATLAB | Python | | |---|---|---| -| `findGeneDeletions` | `single_gene_deletion` {bdg-secondary}`cobrapy` | knock out every gene in turn | -| `findGeneDeletions` (`'sgd'`/`'dgd'`) | `double_gene_deletion` {bdg-secondary}`cobrapy` | pairs of genes | +| `findGeneDeletions` | `single_gene_deletion` {bdg-link-secondary}`cobrapy ` | knock out every gene in turn | +| `findGeneDeletions` (`'sgd'`/`'dgd'`) | `double_gene_deletion` {bdg-link-secondary}`cobrapy ` | pairs of genes | | `getEssentialRxns` | `find_task_essential_reactions` | reactions a task requires | | `deleteUnusedGenes` | `remove_genes` | remove genes, rather than knock them out | -| no equivalent | `moma` {bdg-secondary}`cobrapy` | a knockout's fluxes, staying near the wild type | +| no equivalent | `moma` {bdg-link-secondary}`cobrapy ` | a knockout's fluxes, staying near the wild type | ## Setup diff --git a/docs/guide/editing.md b/docs/guide/editing.md index d5e3a33..2e9ef71 100644 --- a/docs/guide/editing.md +++ b/docs/guide/editing.md @@ -11,8 +11,8 @@ page is the safe way to do each of those. | `changeRxns` | `change_reaction_equations` | replace a reaction's stoichiometry | | `changeGrRules` | `change_gene_reaction_rules` | set or extend gene associations | | `standardizeGrRules` | `gpr_to_dnf` | normalise a GPR | -| `setParam` | `Reaction.bounds` {bdg-secondary}`cobrapy` | change bounds, objective | -| `removeReactions` | `Model.remove_reactions` {bdg-secondary}`cobrapy` | delete reactions | +| `setParam` | `Reaction.bounds` {bdg-link-secondary}`cobrapy ` | change bounds, objective | +| `removeReactions` | `Model.remove_reactions` {bdg-link-secondary}`cobrapy ` | delete reactions | | `removeMets` | `remove_metabolites` | delete metabolites | | `removeGenes`, `deleteUnusedGenes` | `remove_genes` | delete genes | diff --git a/docs/guide/fba.md b/docs/guide/fba.md index 446c433..7b3a3dd 100644 --- a/docs/guide/fba.md +++ b/docs/guide/fba.md @@ -7,15 +7,15 @@ This is the loop every other analysis on this site is built from. | MATLAB | Python | | |---|---|---| -| `setParam` | `Reaction.bounds`, `Model.objective` {bdg-secondary}`cobrapy` | set bounds and the objective | -| `solveLP` | `Model.optimize` {bdg-secondary}`cobrapy` | solve the LP | -| `printFluxes` | `Model.summary` {bdg-secondary}`cobrapy` | show the fluxes that carry material | -| `solveLP` (`minFlux`) | `pfba` {bdg-secondary}`cobrapy` | pick a parsimonious solution among the optima | +| `setParam` | `Reaction.bounds`, `Model.objective` {bdg-link-secondary}`cobrapy ` | set bounds and the objective | +| `solveLP` | `Model.optimize` {bdg-link-secondary}`cobrapy ` | solve the LP | +| `printFluxes` | `Model.summary` {bdg-link-secondary}`cobrapy ` | show the fluxes that carry material | +| `solveLP` (`minFlux`) | `pfba` {bdg-link-secondary}`cobrapy ` | pick a parsimonious solution among the optima | :::{admonition} Where the Python functions come from :class: info Every simulation step on this page is cobrapy, marked -{bdg-secondary}`cobrapy` in the table above. In MATLAB, +{bdg-link-secondary}`cobrapy ` in the table above. In MATLAB, `solveLP` needs neither the COBRA Toolbox nor anything else outside RAVEN. ::: diff --git a/docs/guide/fva.md b/docs/guide/fva.md index fe2ea42..d6e5b1f 100644 --- a/docs/guide/fva.md +++ b/docs/guide/fva.md @@ -9,11 +9,11 @@ requires from one it merely happened to report. | MATLAB | Python | | |---|---|---| -| `getAllowedBounds` | `flux_variability_analysis` {bdg-secondary}`cobrapy` | the range each reaction can take | -| `haveFlux` | `find_blocked_reactions` {bdg-secondary}`cobrapy` | reactions that can carry no flux at all | -| `solveLP` (`minFlux`) | `pfba` {bdg-secondary}`cobrapy` | one representative optimum | -| no equivalent | `loopless_solution` {bdg-secondary}`cobrapy` | an optimum without thermodynamically infeasible loops | -| no equivalent | `add_loopless` {bdg-secondary}`cobrapy` | the constraints behind `loopless="fastSNP"` | +| `getAllowedBounds` | `flux_variability_analysis` {bdg-link-secondary}`cobrapy ` | the range each reaction can take | +| `haveFlux` | `find_blocked_reactions` {bdg-link-secondary}`cobrapy ` | reactions that can carry no flux at all | +| `solveLP` (`minFlux`) | `pfba` {bdg-link-secondary}`cobrapy ` | one representative optimum | +| no equivalent | `loopless_solution` {bdg-link-secondary}`cobrapy ` | an optimum without thermodynamically infeasible loops | +| no equivalent | `add_loopless` {bdg-link-secondary}`cobrapy ` | the constraints behind `loopless="fastSNP"` | | no equivalent | `find_good_reactions` | reactions whose range is real rather than a loop | ## Setup diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 13e3ded..b1c2ecc 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -8,11 +8,11 @@ gene. Every later page assumes these operations. | MATLAB | Python | | |---|---|---| | `readYAMLmodel` | `read_yaml_model` | read a RAVEN YAML model | -| `importModel` | `read_sbml_model` {bdg-secondary}`cobrapy` | read an SBML model | -| `printModelStats` | model attributes {bdg-secondary}`cobrapy` | how big the model is | -| `getIndexes` | `get_by_id` {bdg-secondary}`cobrapy` | look something up by identifier | -| `constructEquations` | `Reaction.reaction` {bdg-secondary}`cobrapy` | a reaction as a readable string | -| `getElementalBalance` | `check_mass_balance` {bdg-secondary}`cobrapy` | is a reaction balanced | +| `importModel` | `read_sbml_model` {bdg-link-secondary}`cobrapy ` | read an SBML model | +| `printModelStats` | model attributes {bdg-link-secondary}`cobrapy ` | how big the model is | +| `getIndexes` | `get_by_id` {bdg-link-secondary}`cobrapy ` | look something up by identifier | +| `constructEquations` | `Reaction.reaction` {bdg-link-secondary}`cobrapy ` | a reaction as a readable string | +| `getElementalBalance` | `check_mass_balance` {bdg-link-secondary}`cobrapy ` | is a reaction balanced | ## Setup diff --git a/docs/guide/index.md b/docs/guide/index.md index c98d149..610f2f6 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -17,7 +17,7 @@ original RAVEN paper. Both are MATLAB only. :::{admonition} cobrapy :class: info Functions that come from cobrapy rather than raven-toolbox carry a -{bdg-secondary}`cobrapy` badge, their import line shows where +{bdg-link-secondary}`cobrapy ` badge, their import line shows where they live (`from cobra.io import read_sbml_model`), and the badge links to the cobrapy documentation. The [function mapping](../matlab-vs-python.md) lists every such function. diff --git a/docs/guide/io.md b/docs/guide/io.md index 9e2183f..1db90a7 100644 --- a/docs/guide/io.md +++ b/docs/guide/io.md @@ -7,8 +7,8 @@ directory layout a Git-maintained model repository expects. | MATLAB | Python | | |---|---|---| -| `importModel` | `read_sbml_model` {bdg-secondary}`cobrapy` | read SBML | -| `exportModel` | `write_sbml_model` {bdg-secondary}`cobrapy` | write SBML | +| `importModel` | `read_sbml_model` {bdg-link-secondary}`cobrapy ` | read SBML | +| `exportModel` | `write_sbml_model` {bdg-link-secondary}`cobrapy ` | write SBML | | `readYAMLmodel` | `read_yaml_model` | read RAVEN YAML | | `writeYAMLmodel` | `write_yaml_model` | write RAVEN YAML | | `exportToExcelFormat` | `export_to_excel` | write the RAVEN Excel format | diff --git a/docs/guide/media.md b/docs/guide/media.md index f3e6422..2733f50 100644 --- a/docs/guide/media.md +++ b/docs/guide/media.md @@ -8,10 +8,10 @@ a condition as reviewable data instead of a paragraph of bound-setting code. | MATLAB | Python | | |---|---|---| -| `getExchangeRxns` | `Model.exchanges` {bdg-secondary}`cobrapy` | find the exchange reactions | -| `setExchangeBounds` | `Model.medium` {bdg-secondary}`cobrapy` | set a whole medium, closing the rest | +| `getExchangeRxns` | `Model.exchanges` {bdg-link-secondary}`cobrapy ` | find the exchange reactions | +| `setExchangeBounds` | `Model.medium` {bdg-link-secondary}`cobrapy ` | set a whole medium, closing the rest | | `setParam` | `set_reaction_bounds` | set one reaction's bounds | -| `getMinimalMedium` | `minimal_medium` {bdg-secondary}`cobrapy` | the smallest medium that still supports growth | +| `getMinimalMedium` | `minimal_medium` {bdg-link-secondary}`cobrapy ` | the smallest medium that still supports growth | | `applyCondition` | `apply_condition`, `load_condition` | apply a condition file | ## Setup diff --git a/docs/guide/model-structure.md b/docs/guide/model-structure.md index b549a51..f48c558 100644 --- a/docs/guide/model-structure.md +++ b/docs/guide/model-structure.md @@ -12,7 +12,7 @@ of what you need to translate a script between the two. | `sortIdentifiers` | `sort_identifiers` | sort reactions, metabolites and genes by id | | `getIndexes` | `parse_name_comp` | split a `name[comp]` token | | no equivalent | `subsystem_to_str` | one subsystem string, whatever the source stored | -| `addIdentifierPrefix`, `removeIdentifierPrefix` | handled on read/write {bdg-secondary}`cobrapy` | SBML identifier prefixes | +| `addIdentifierPrefix`, `removeIdentifierPrefix` | handled on read/write {bdg-link-secondary}`cobrapy ` | SBML identifier prefixes | | `ravenCobraWrapper` | not needed | convert between RAVEN and COBRA structs | ## The correspondence diff --git a/docs/guide/quality-control.md b/docs/guide/quality-control.md index 9a5e5d3..99d47da 100644 --- a/docs/guide/quality-control.md +++ b/docs/guide/quality-control.md @@ -11,9 +11,9 @@ nothing. |---|---|---| | `checkModelStruct` | `check_model` | structural problems | | `getElementalBalance` | `get_elemental_balance` | mass balance, reaction by reaction | -| `haveFlux` | `find_blocked_reactions` {bdg-secondary}`cobrapy` | reactions that can never carry flux | +| `haveFlux` | `find_blocked_reactions` {bdg-link-secondary}`cobrapy ` | reactions that can never carry flux | | `canExchange` | `analyse_topology` | which metabolites the model can make, or consume, given its medium | -| `findLeakMetabolite` | `Model.optimize` on a demand {bdg-secondary}`cobrapy` | can the model make something from **nothing** | +| `findLeakMetabolite` | `Model.optimize` on a demand {bdg-link-secondary}`cobrapy ` | can the model make something from **nothing** | | `gapReport` | `check_model` + `analyse_topology` | one summary of the gaps | ## Setup diff --git a/docs/guide/sampling.md b/docs/guide/sampling.md index d9d75dd..5ce5775 100644 --- a/docs/guide/sampling.md +++ b/docs/guide/sampling.md @@ -13,7 +13,7 @@ is usually 0, usually 10, or evenly spread; a sample does. | `sampleACHR` | `random_sampling` (`method='achr'`) | hit-and-run MCMC, the default | | `sampleCHRR` | `random_sampling` (`method='chrr'`) | hit-and-run with rounding, for thin polytopes | | no equivalent | `find_good_reactions` | reactions usable as random objectives | -| `getAllowedBounds` | `flux_variability_analysis` {bdg-secondary}`cobrapy` | the ranges sampling fills in | +| `getAllowedBounds` | `flux_variability_analysis` {bdg-link-secondary}`cobrapy ` | the ranges sampling fills in | ## Setup diff --git a/docs/guide/solvers.md b/docs/guide/solvers.md index 78515e7..2c9872a 100644 --- a/docs/guide/solvers.md +++ b/docs/guide/solvers.md @@ -8,10 +8,10 @@ read what it gives back. | MATLAB | Python | | |---|---|---| -| `setRavenSolver` | `Configuration` {bdg-secondary}`cobrapy` | choose the solver | -| `checkInstallation` | `Configuration` {bdg-secondary}`cobrapy` | check the solver works | -| `solveLP` | `Model.optimize` {bdg-secondary}`cobrapy` | solve, and get a solution object | -| `optimizeProb` | `Model.solver` {bdg-secondary}`cobrapy` | solve a problem the toolbox built for you | +| `setRavenSolver` | `Configuration` {bdg-link-secondary}`cobrapy ` | choose the solver | +| `checkInstallation` | `Configuration` {bdg-link-secondary}`cobrapy ` | check the solver works | +| `solveLP` | `Model.optimize` {bdg-link-secondary}`cobrapy ` | solve, and get a solution object | +| `optimizeProb` | `Model.solver` {bdg-link-secondary}`cobrapy ` | solve a problem the toolbox built for you | ## Setup From f725b325d6d1ac5133064e13622ed1a70e8f4539 Mon Sep 17 00:00:00 2001 From: Eduard Kerkhoven Date: Wed, 9 Sep 2026 19:47:29 +0200 Subject: [PATCH 4/4] Delete file --- CLAUDE.md | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 88b5758..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,28 +0,0 @@ -# raven-docs - -## Documentation prose style - -This site's readers are not all native English speakers. Prose has to be -direct and literal, not just factually correct. - -No idioms, figures of speech, or headline-style fragments that drop the -subject or verb for effect. A heading or sentence should parse the same way -for a reader translating it word by word as it does for a native speaker. -Two examples flagged and rewritten in a live sweep of this repo: - -- "Names do not convert mechanically" (a heading) implies its meaning through - word choice ("mechanically" standing in for "automatically" or "by a fixed - rule") rather than stating it. -- "Same verdicts, very different cost" (a heading) is a sentence fragment: the - subject and verb are implied, not written, and the reader has to supply - "they give" and "but they have" to parse it. - -Rewrite this kind of phrasing as a complete, literal sentence that says what -it means. Direct is not the same as dumbed down: keep the technical content -and the precision, drop only the cleverness. - -No em dashes, anywhere: not in prose, headings, table cells, or generated -strings. Use the punctuation the sentence calls for instead: a comma where -the clause continues, a semicolon where it is independent, a colon where -what follows defines or enumerates what precedes it, parentheses for a -matched pair around an aside.