FBA with crowding

Here we will use flux_balance_analysis to explore the metabolism of the toy E. coli model that additionally respects common protein crowding constraints. In particular, the model is limited by the amount of protein required to run certain reactions. If that data is available, the predictions are accordingly more realistic. See Beg, et al., "Intracellular crowding defines the mode and sequence of substrate uptake by Escherichia coli and constrains its metabolic activity.", Proceedings of the National Academy of Sciences,2007 for more details.

As usual, the same model modification can be transparently used with many other analysis functions, including flux_variability_analysis and parsimonious_flux_balance_analysis.

!isfile("e_coli_core.xml") &&

using COBREXA, Tulip

model = load_model("e_coli_core.xml")
Metabolic model of type SBMLModel
sparse([8, 10, 21, 43, 50, 51, 8, 9, 6, 12  …  33, 66, 68, 72, 23, 26, 33, 72, 22, 33], [1, 1, 1, 1, 1, 1, 2, 2, 3, 3  …  93, 93, 93, 93, 94, 94, 94, 94, 95, 95], [-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0  …  1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0], 72, 95)
Number of reactions: 95
Number of metabolites: 72


To describe the protein crowding, each of the enzymes that catalyze the reactions gets an associated weight per unit of reaction conversion rate. The total sum of all weights multiplied by the flux in the model must be lower than 1.

The weights are prepared in a dictionary; for simplicity we assume that the relative weight of all enzymes is random between 0.002 and 0.005. enzymes are of the same size. Reactions that are not present in the dictionary (typically exchanges) are ignored.

import Random
Random.seed!(1) # for repeatability of random numbers below

rid_crowding_weight = Dict(
rid => 0.002 + 0.003 * rand() for rid in reactions(model) if
!looks_like_biomass_reaction(rid) && !looks_like_exchange_reaction(rid)
)
Dict{String, Float64} with 74 entries:
"R_ACONTb"   => 0.00474479
"R_GLNS"     => 0.00419165
"R_SUCOAS"   => 0.00285974
"R_TPI"      => 0.00321767
"R_PPC"      => 0.00404847
"R_O2t"      => 0.00281663
"R_G6PDH2r"  => 0.00311648
"R_TALA"     => 0.00475675
"R_PPCK"     => 0.00471792
"R_PGL"      => 0.00362231
"R_H2Ot"     => 0.0025905
"R_GLNabc"   => 0.00329044
"R_MALt2_2"  => 0.00328254
"R_ME2"      => 0.0033115
"R_GAPD"     => 0.00460608
"R_CS"       => 0.00200405
"R_ETOHt2r"  => 0.00203739
"R_ACKr"     => 0.00409648
"R_PGK"      => 0.00241937
⋮            => ⋮

With this, the crowding constraints are added with modification add_crowding_constraints:

loopless_crowding_fluxes = flux_balance_analysis_dict(
model,
Tulip.Optimizer;
)
Dict{String, Float64} with 95 entries:
"R_EX_fum_e"    => 0.0
"R_ACONTb"      => 0.677983
"R_GLNS"        => 0.160683
"R_SUCOAS"      => -1.44063e-9
"R_TPI"         => 6.54899
"R_EX_pi_e"     => -2.3117
"R_PPC"         => 1.80075
"R_O2t"         => 13.1643
"R_G6PDH2r"     => 5.38733
"R_TALA"        => 1.68335
"R_PPCK"        => 1.48421e-10
"R_EX_lac__D_e" => 2.56015e-10
"R_PGL"         => 5.38733
"R_H2Ot"        => -18.4683
"R_GLNabc"      => 0.0
"R_EX_co2_e"    => 13.8908
"R_EX_gln__L_e" => 0.0
"R_EX_nh4_e"    => -3.42655
"R_MALt2_2"     => 0.0
⋮               => ⋮
flux_summary(loopless_crowding_fluxes)
Biomass
R_BIOMASS_Ecoli_core_w_GAM: 0.6284
Import
R_EX_o2_e:                  -13.1643
R_EX_glc__D_e:              -8.9698
R_EX_nh4_e:                 -3.4266
R_EX_pi_e:                  -2.3117
Export
R_EX_ac_e:                  6.5931
R_EX_co2_e:                 13.8908
R_EX_h2o_e:                 18.4683
R_EX_h_e:                   19.1989