CRM-FBA experiments

CRM-coupled dynamic FBA. Each experiment in this suite runs a genome-scale metabolic model (GSM) under Flux Balance Analysis, with exchange-reaction lower bounds set by a Consumer Resource Model (CRM) from a pluggable registry (MacArthur, Adaptive, MCRM, MiCRM, Monod). The figures separate the two layers explicitly — panel (B) shows the CRM-prescribed uptake rate u_a(t) (the input to EX_rxn.lower_bound = −u_a), panel (C) shows the FBA-realized exchange flux v_a(t) next to the CRM envelope so the coupling is visible at a glance.
Generated: 2026-04-15 15:46:10 UTC
On: LT-0919936
Commit: 936698b1
Source: vivarium-collective/CRM-FBA

Diauxie

Sequential substrate utilization · CRM: monod

Classical Monod CRM coupled to the E. coli core GSM. With high initial glucose, FBA preferentially oxidizes glucose and secretes some acetate. Once glucose is depleted, the Monod uptake rate on acetate becomes non-negligible and FBA switches to acetate consumption — the canonical diauxic shift.

Result

diauxie

Composition

diauxie bigraph

Summary

PhenomenonSequential substrate utilization
GSMtextbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMmonod
Integration360 steps × 0.05 hr = 18.0 hr simulated
Wall-clock time0.21 s
Final biomass1.377 gDW/L
Final glucose0.000 mmol/L
Final acetate0.000 mmol/L
Peak μ (FBA)0.882 1/hr
Peak glucose CRM→FBAu=9.68   ·   |v|=9.68   mmol/gDW/hr

Configuration

model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = monod
crm.params        = {'kinetic_params': {'glucose': (0.5, 10.0), 'acetate': (0.5, 3.0)}}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -20.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Overflow

Crabtree-like acetate secretion · CRM: macarthur

MacArthur external-resource CRM drives glucose uptake while the oxygen exchange is tightly capped (EX_o2_e lower = -5). Under O2 limitation the LP cannot fully oxidize the influx and secretes acetate as overflow — a Crabtree-like phenotype — even though no acetate was initially present.

Result

overflow

Composition

overflow bigraph

Summary

PhenomenonCrabtree-like acetate secretion
GSMtextbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMmacarthur
Integration300 steps × 0.05 hr = 15.0 hr simulated
Wall-clock time0.10 s
Final biomass0.908 gDW/L
Final glucose0.003 mmol/L
Final acetate1.562 mmol/L
Peak μ (FBA)0.608 1/hr
Peak glucose CRM→FBAu=14.40   ·   |v|=14.40   mmol/gDW/hr
Peak acetate CRM→FBAu=4.14   ·   |v|=3.35   mmol/gDW/hr

Configuration

model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = macarthur
crm.params        = {'c': {'glucose': 1.2, 'acetate': 0.4}, 'resource_mode': 'external'}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -5.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Adaptive

Dynamic trait reallocation · CRM: adaptive

Adaptive CRM with an internal allocation vector A_a per resource, constrained by an energy budget E_star. Initial allocation is skewed to glucose (A0=[0.95, 0.05]) and the oxygen exchange is capped so FBA secretes acetate as overflow while glucose is abundant. Once glucose depletes, r_glucose → 0 so the gradient on A_glucose vanishes while A_acetate keeps climbing under the Picciani-Mori rule — the allocation vector reallocates toward acetate and growth continues on the acetate pool that the cell itself produced.

Result

adaptive

Composition

adaptive bigraph

Summary

PhenomenonDynamic trait reallocation
GSMtextbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMadaptive
Integration480 steps × 0.05 hr = 24.0 hr simulated
Wall-clock time0.37 s
Final biomass0.784 gDW/L
Final glucose0.000 mmol/L
Final acetate0.019 mmol/L
Peak μ (FBA)0.493 1/hr
Peak glucose CRM→FBAu=9.51   ·   |v|=9.51   mmol/gDW/hr
Peak acetate CRM→FBAu=4.61   ·   |v|=4.61   mmol/gDW/hr

Configuration

model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = adaptive
crm.params        = {'v': {'glucose': 10.0, 'acetate': 5.0}, 'K': {'glucose': 0.5, 'acetate': 0.5}, 'lam': 0.6, 'E_star': 1.0, 'A0': {'glucose': 0.9, 'acetate': 0.1}, 'n_substeps': 50}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -6.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Tilman

R-independent uptake · CRM: macarthur

MacArthur CRM in 'tilman' mode: uptake rate u_a = c_a is independent of R_a. FBA drives glucose hard and at a constant rate until the extracellular concentration is exhausted, giving a sharply-cornered depletion profile characteristic of Tilman-style resource competition.

Result

tilman

Composition

tilman bigraph

Summary

PhenomenonR-independent uptake
GSMtextbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMmacarthur
Integration300 steps × 0.05 hr = 15.0 hr simulated
Wall-clock time0.10 s
Final biomass1185.977 gDW/L
Final glucose0.000 mmol/L
Final acetate0.000 mmol/L
Peak μ (FBA)0.797 1/hr
Peak glucose CRM→FBAu=8.00   ·   |v|=8.00   mmol/gDW/hr
Peak acetate CRM→FBAu=3.00   ·   |v|=0.00   mmol/gDW/hr

Configuration

model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = macarthur
crm.params        = {'c': {'glucose': 8.0, 'acetate': 3.0}, 'resource_mode': 'tilman'}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -20.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Cross Feed

Metabolic leakage and re-uptake · CRM: micrm

MiCRM-style mass-action uptake of glucose and acetate on a single organism. FBA secretes acetate as a byproduct while glucose is abundant (positive extracellular acetate trajectory); once glucose drops, the accumulated acetate pool supports a second growth phase — a single-species analogue of community cross-feeding.

Result

cross_feed

Composition

cross_feed bigraph

Summary

PhenomenonMetabolic leakage and re-uptake
GSMtextbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMmicrm
Integration360 steps × 0.05 hr = 18.0 hr simulated
Wall-clock time0.12 s
Final biomass0.663 gDW/L
Final glucose0.016 mmol/L
Final acetate0.836 mmol/L
Peak μ (FBA)0.444 1/hr
Peak glucose CRM→FBAu=8.00   ·   |v|=8.00   mmol/gDW/hr
Peak acetate CRM→FBAu=1.13   ·   |v|=1.10   mmol/gDW/hr

Configuration

model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = micrm
crm.params        = {'c': {'glucose': 1.0, 'acetate': 0.3}}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -6.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Nutrient Sweep

Saturating yield curve · CRM: monod

Sweep over initial glucose (1-80 mmol/L) with the Monod diauxie setup. Plot final biomass and apparent biomass yield per mmol glucose consumed. Biomass saturates with resource availability; apparent yield drops at high glucose as more carbon exits as acetate/CO2 overflow.

Result

nutrient_sweep

Composition

nutrient_sweep bigraph

Summary

PhenomenonSaturating yield curve
GSMtextbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMmonod
Integration240 steps × 0.05 hr = 12.0 hr simulated
Wall-clock time1.24 s
Rangeglucose0 ∈ [1.0, 80.0] mmol/L (7 points)
Biomass range0.099 → 7.421 gDW/L

Configuration

model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = monod
crm.params        = {'kinetic_params': {'glucose': (0.5, 10.0), 'acetate': (0.5, 3.0)}}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -20.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Community

Niche differentiation and cross-feeding · CRM: monod

Two E. coli core GSMs share a single glucose+acetate pool with no spatial separation. Species 'glucose_specialist' has a strong Monod preference for glucose (high Vmax_glc, low Vmax_ac) and a tight O2 cap that forces acetate overflow. Species 'acetate_specialist' has low glucose affinity and high acetate Vmax. Early on the glucose specialist dominates, secreting acetate; the acetate specialist then grows on the acetate byproduct — niche partitioning by cross-feeding, visible as two offset growth phases on the same GSM.

Result

community

Composition

community bigraph

Summary

PhenomenonNiche differentiation and cross-feeding
GSM (glucose_specialist)textbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
GSM (acetate_specialist)textbook — Escherichia coli (core GSM, 95 rxns)
biomass reaction: Biomass_Ecoli_core
CRMmonod
Integration360 steps × 0.05 hr = 18.0 hr simulated
Wall-clock time0.24 s
Final biomass (glucose_specialist)0.850 gDW/L   ·   peak μ = 0.563 1/hr
Final biomass (acetate_specialist)0.032 gDW/L   ·   peak μ = 0.221 1/hr
Final glucose (shared pool)0.000 mmol/L
Final acetate (shared pool)9.620 mmol/L

Configuration

# glucose_specialist
model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = monod
crm.params        = {'kinetic_params': {'glucose': (0.3, 12.0), 'acetate': (2.0, 1.0)}}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -6.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

# acetate_specialist
model_file        = 'textbook'   # Escherichia coli (core GSM, 95 rxns)
biomass_reaction  = 'Biomass_Ecoli_core'
crm.type          = monod
crm.params        = {'kinetic_params': {'glucose': (5.0, 1.5), 'acetate': (0.2, 6.0)}}
substrate_update_reactions = {'glucose': 'EX_glc__D_e', 'acetate': 'EX_ac_e'}
bounds            = {'EX_o2_e': {'lower': -20.0, 'upper': 1000.0}, 'ATPM': {'lower': 1.0, 'upper': 1.0}}

Composite Document

Run Summary

Experiment Phenomenon CRM GSM Sim time Wall-clock
DiauxieSequential substrate utilizationmonodtextbook18.0 h0.21 s
OverflowCrabtree-like acetate secretionmacarthurtextbook15.0 h0.10 s
AdaptiveDynamic trait reallocationadaptivetextbook24.0 h0.37 s
TilmanR-independent uptakemacarthurtextbook15.0 h0.10 s
Cross FeedMetabolic leakage and re-uptakemicrmtextbook18.0 h0.12 s
Nutrient SweepSaturating yield curvemonodtextbook12.0 h1.24 s
CommunityNiche differentiation and cross-feedingmonodtextbook, textbook18.0 h0.24 s
Total wall-clock2.38 s

How to reproduce

Every experiment in this report is generated by the same CLI (crm_dfba.experiments.test_suite) running against the genome-scale metabolic models bundled under crm_dfba/models/. Clone the repo and run the suite to regenerate this page.

Re-run locally

git clone https://github.com/vivarium-collective/CRM-FBA
cd CRM-FBA
git checkout 936698b1
pip install -e .
python -m crm_dfba.experiments.test_suite

Subset / headless

python -m crm_dfba.experiments.test_suite --only diauxie community
python -m crm_dfba.experiments.test_suite --no-open

Author a new experiment

Add an Experiment(...) entry to EXPERIMENT_REGISTRY in crm_dfba/experiments/test_suite.py. Point build_cfg at a CRM+GSM config (helper _cfg_from(model_key, crm, bounds) uses the bundled model registry). For multi-consumer experiments set runner_override=_simulate_community and list species in extra_meta['species'].