CycleFreeFlux
CycleFreeFlux essentially defines a L1-parsimonious model which can be used to run a cycle-free FBA and FVA. In COBREXA, this is best done by reusing linear_parsimonious_flux_balance_analysis
.
First, let's get a model, create a constraint tree with the model, and ask for explicitly materializing constraints for the exchanges:
using COBREXA
download_model(
"http://bigg.ucsd.edu/static/models/e_coli_core.json",
"e_coli_core.json",
"7bedec10576cfe935b19218dc881f3fb14f890a1871448fc19a9b4ee15b448d8",
)
import JSONFBCModels, HiGHS
model = load_model("e_coli_core.json")
cs = flux_balance_constraints(model, interface = :identifier_prefixes)
ConstraintTrees.Tree{ConstraintTrees.Constraint} with 5 elements:
:coupling => ConstraintTrees.Tree{ConstraintTrees.Constraint}(#= 0 …
:flux_stoichiometry => ConstraintTrees.Tree{ConstraintTrees.Constraint}(#= 72…
:fluxes => ConstraintTrees.Tree{ConstraintTrees.Constraint}(#= 95…
:interface => ConstraintTrees.Tree{ConstraintTrees.Constraint}(#= 3 …
:objective => ConstraintTrees.Constraint(ConstraintTrees.LinearValue…
We will also need some existing solution of the model – CycleFreeFlux algorithm uses this one as a reference for fixing the exchange reaction flux.
some_flux =
optimized_values(cs, objective = cs.objective.value, optimizer = HiGHS.Optimizer)
ConstraintTrees.Tree{Float64} with 5 elements:
:coupling => ConstraintTrees.Tree{Float64}(#= 0 elements =#)
:flux_stoichiometry => ConstraintTrees.Tree{Float64}(#= 72 elements =#)
:fluxes => ConstraintTrees.Tree{Float64}(#= 95 elements =#)
:interface => ConstraintTrees.Tree{Float64}(#= 3 elements =#)
:objective => 0.873922
(Ideally, we should use a solving method that gives a more unique flux, but for this example a simple FBA optimum will do.)
With this in hand, we can start the CycleFreeFlux workflow by placing constraints on exchange reactions in a linear-parsimonious model:
import ConstraintTrees as C
cs = linear_parsimonious_flux_balance_constraints(model)
cs *=
:fixed_exchanges^C.ConstraintTree(
k => C.Constraint(cs.fluxes[k].value, relative_tolerance_bound(0.999)(v)) for
(k, v) in some_flux.interface.exchanges
)
ConstraintTrees.Tree{ConstraintTrees.Constraint} with 9 elements:
:coupling => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:directional_flux_balance => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:fixed_exchanges => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:flux_stoichiometry => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:fluxes => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:fluxes_forward => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:fluxes_reverse => ConstraintTrees.Tree{ConstraintTrees.Constraint}…
:objective => ConstraintTrees.Constraint(ConstraintTrees.Linea…
:parsimonious_objective => ConstraintTrees.Constraint(ConstraintTrees.Linea…
(We purposefully made the constraints a little less strict by using relative_tolerance_bound
– the toy E. coli model would otherwise display no variability at all.)
Now we can get a L1-parsimonious (thus cycle-free) solution of the model with the predefined exchanges:
cycle_free_flux = parsimonious_optimized_values(
cs,
objective = cs.objective.value,
objective_value = some_flux.objective,
parsimonious_objective = cs.parsimonious_objective.value,
optimizer = HiGHS.Optimizer,
)
cycle_free_flux.fluxes
ConstraintTrees.Tree{Float64} with 95 elements:
:ACALD => 0.0
:ACALDt => 0.0
:ACKr => 0.0
:ACONTa => 6.00725
:ACONTb => 6.00725
:ACt2r => 0.0
:ADK1 => 0.0
:AKGDH => 5.06438
:AKGt2r => 0.0
:ALCD2x => 0.0
:ATPM => 8.39
:ATPS4r => 45.514
:BIOMASS_Ecoli_core_w_GAM => 0.873922
:CO2t => -22.8098
:CS => 6.00725
:CYTBD => 43.599
:D_LACt2 => 0.0
:ENO => 14.7161
:ETOHt2r => 0.0
⋮ => ⋮
CycleFreeFVA
With this in hand, we can also run the cycle-free flux variability analysis (again with an added bit of tolerances in both the objective and parsimonious bounds):
cs.objective.bound = C.Between(cycle_free_flux.objective * 0.999, Inf)
cs.parsimonious_objective.bound =
C.Between(0, cycle_free_flux.parsimonious_objective * 1.001)
var = constraints_variability(cs, cs.fluxes, optimizer = HiGHS.Optimizer)
ConstraintTrees.Tree{Tuple{Union{Nothing, Float64}, Union{Nothing, Float64}}} with 95 elements:
:ACALD => (-0.0, 0.0)
:ACALDt => (-0.0, 0.0)
:ACKr => (-0.0, 0.0)
:ACONTa => (5.92071, 6.08235)
:ACONTb => (5.92071, 6.08235)
:ACt2r => (-0.0, 0.0)
:ADK1 => (-0.0, 0.108535)
:AKGDH => (4.48889, 5.14042)
:AKGt2r => (-0.0, 9.63674e-13)
:ALCD2x => (-0.0, 0.0)
:ATPM => (8.39, 8.51247)
:ATPS4r => (45.3147, 45.6379)
:BIOMASS_Ecoli_core_w_GAM => (0.873048, 0.873922)
:CO2t => (-22.8311, -22.7898)
:CS => (5.92071, 6.08235)
:CYTBD => (43.561, 43.6426)
:D_LACt2 => (1.39223e-13, 0.0)
:ENO => (14.6209, 14.7825)
:ETOHt2r => (-0.0, -5.77316e-14)
⋮ => ⋮
CycleFree sampling
Naturally, we can also run flux sampling from the above model. To implement this, we follow the implementation of flux_sample
–- first we generate the warmup:
warmup = vcat(
(
transpose(v) for (_, vs) in constraints_variability(
cs,
cs.fluxes,
optimizer = HiGHS.Optimizer,
output = (_, om) -> variable_vector(om),
output_type = Vector{Float64},
) for v in vs
)...,
)
190×285 Matrix{Float64}:
7.40268 -0.0 4.63538 -15.9497 5.18557 … -0.0 -0.0 -0.0 -0.0
7.3821 -0.0 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.40268 -0.0 4.63538 -15.9497 5.18557 -0.0 -0.0 -0.0 -0.0
7.3821 -0.0 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.40268 -0.0 4.63538 -15.9497 5.18557 -0.0 -0.0 -0.0 -0.0
7.3821 -0.0 4.57806 -15.927 5.24023 … -0.0 -0.0 -0.0 -0.0
7.3821 -0.0 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.54579 -0.0 5.0732 -16.0886 4.74305 -0.0 -0.0 -0.0 -0.0
7.3821 -0.0 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.54579 -0.0 5.0732 -16.0886 4.74305 -0.0 -0.0 -0.0 -0.0
⋮ ⋱
7.3821 -0.0 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.40268 -0.0 4.63538 -15.9497 5.18557 -0.0 -0.0 -0.0 -0.0
7.54579 -0.0 5.0732 -16.0886 4.74305 -0.0 -0.0 -0.0 -0.0
7.54579 -0.0 5.0732 -16.0886 4.74305 -0.0 -0.0 -0.0 -0.0
7.3821 -2.27792e-13 4.57806 -15.927 5.24023 … -0.0 -0.0 -0.0 -0.0
7.54579 -0.0 5.0732 -16.0886 4.74305 -0.0 -0.0 -0.0 -0.0
7.3821 -2.27792e-13 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.3821 -0.0 4.57806 -15.927 5.24023 -0.0 -0.0 -0.0 -0.0
7.54579 -0.0 5.0732 -16.0886 4.74305 -0.0 -0.0 -0.0 -0.0
Next, we can run the sampling:
sample = sample_constraints(
sample_chain_achr,
cs,
start_variables = warmup,
seed = UInt(1234),
output = cs.fluxes,
n_chains = 10,
collect_iterations = collect(10:15),
)
ConstraintTrees.Tree{Vector{Float64}} with 95 elements:
:ACALD => [-7.85929e-15, 3.12233e-15, -6.32648e-15, -9.255…
:ACALDt => [-3.35535e-15, 7.30498e-15, -6.93217e-16, -4.301…
:ACKr => [-2.25938e-14, -1.25307e-14, -1.87866e-14, -2.04…
:ACONTa => [5.99813, 6.00102, 5.99386, 5.9927, 5.99009, 5.9…
:ACONTb => [5.99813, 6.00102, 5.99386, 5.9927, 5.99009, 5.9…
:ACt2r => [-2.26604e-14, -1.26102e-14, -1.88598e-14, -2.05…
:ADK1 => [0.00366918, 0.00229605, 0.00255894, 0.00289447,…
:AKGDH => [4.97009, 4.92654, 4.93649, 4.92894, 4.95038, 4.…
:AKGt2r => [3.21028e-14, 4.66312e-14, 2.72193e-14, 1.34945e…
:ALCD2x => [-3.86995e-15, -3.7229e-15, -5.06453e-15, -4.348…
:ATPM => [8.391, 8.39171, 8.39097, 8.3908, 8.39019, 8.390…
:ATPS4r => [45.5143, 45.509, 45.5227, 45.5218, 45.5294, 45.…
:BIOMASS_Ecoli_core_w_GAM => [0.873127, 0.87315, 0.87316, 0.87315, 0.873184, …
:CO2t => [-22.8174, -22.8185, -22.8188, -22.8189, -22.819…
:CS => [5.99813, 6.00102, 5.99386, 5.9927, 5.99009, 5.9…
:CYTBD => [43.616, 43.6182, 43.6186, 43.619, 43.619, 43.62…
:D_LACt2 => [-2.08644e-14, -2.16803e-14, -2.07692e-14, -2.34…
:ENO => [14.6991, 14.7022, 14.6952, 14.6939, 14.6916, 14…
:ETOHt2r => [-4.90694e-15, -3.98458e-15, -5.63877e-15, -5.09…
⋮ => ⋮
The results can be observed (and usually plotted) from the sample vectors, such as the one for oxygen exchange:
sample.EX_o2_e
11400-element Vector{Float64}:
-21.80801279761615
-21.80909965602572
-21.80930963740098
-21.80947899277754
-21.809475488922107
-21.810421483414107
-21.80854524250612
-21.80880422807698
-21.809512140853517
-21.80952709530663
⋮
-21.810011276079326
-21.810020653415503
-21.808622072753835
-21.808747348916107
-21.809865327092407
-21.809303155329953
-21.81135072741717
-21.810153001483112
-21.81051289673462
This page was generated using Literate.jl.