Skip to content

Commit 65f25b3

Browse files
authored
Merge pull request #800 from LCSB-BioCore/sew-fba-tests-etc
Start getting FBA to work
2 parents 4d1d8d9 + fe1ef35 commit 65f25b3

24 files changed

+602
-123
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ Manifest.toml
2020

2121
# ignore container files
2222
*.sif
23+
24+
# ignore models
25+
*.xml
26+
*.json
27+
*.mat

.gitlab-ci.yml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ variables:
7171
before_script:
7272
- docker login -u $CI_USER_NAME -p $GITLAB_ACCESS_TOKEN $CI_REGISTRY
7373

74-
.global_julia18: &global_julia18
74+
.global_julia19: &global_julia19
7575
variables:
76-
JULIA_VER: "v1.8.3"
76+
JULIA_VER: "v1.9.4"
7777

7878
.global_julia16: &global_julia16
7979
variables:
@@ -120,26 +120,24 @@ variables:
120120
# any available docker and current julia
121121
#
122122

123-
docker:julia1.8:
123+
docker:julia1.9:
124124
stage: test
125125
image: $CI_REGISTRY/r3/docker/julia-custom
126126
script:
127127
- julia --check-bounds=yes --inline=yes --project=@. -e "import Pkg; Pkg.test(; coverage = true)"
128-
after_script:
129-
- julia --project=test/coverage test/coverage/coverage-summary.jl
130128
<<: *global_trigger_pull_request
131129

132130
#
133131
# The required compatibility test to pass on branches&tags before the docs get
134132
# built & deployed
135133
#
136134

137-
linux:julia1.8:
135+
linux:julia1.9:
138136
stage: test
139137
tags:
140138
- slave01
141139
<<: *global_trigger_full_tests
142-
<<: *global_julia18
140+
<<: *global_julia19
143141
<<: *global_env_linux
144142

145143
linux:julia1.6:
@@ -154,22 +152,22 @@ linux:julia1.6:
154152
# Additional platform&environment compatibility tests
155153
#
156154

157-
windows8:julia1.8:
155+
windows8:julia1.9:
158156
stage: test-compat
159157
<<: *global_trigger_compat_tests
160-
<<: *global_julia18
158+
<<: *global_julia19
161159
<<: *global_env_win8
162160

163-
windows10:julia1.8:
161+
windows10:julia1.9:
164162
stage: test-compat
165163
<<: *global_trigger_compat_tests
166-
<<: *global_julia18
164+
<<: *global_julia19
167165
<<: *global_env_win10
168166

169-
mac:julia1.8:
167+
mac:julia1.9:
170168
stage: test-compat
171169
<<: *global_trigger_compat_tests
172-
<<: *global_julia18
170+
<<: *global_julia19
173171
<<: *global_env_mac
174172

175173
windows8:julia1.6:

Project.toml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,32 @@ StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
1818

1919
[compat]
2020
AbstractFBCModels = "0.2"
21+
Aqua = "0.7"
2122
Clarabel = "0.3"
22-
ConstraintTrees = "0.4"
23+
ConstraintTrees = "0.5"
2324
DistributedData = "0.2"
2425
DocStringExtensions = "0.8, 0.9"
26+
Downloads = "1"
27+
GLPK = "1"
28+
JSONFBCModels = "0.1"
2529
JuMP = "1"
30+
SBMLFBCModels = "0.1"
31+
SHA = "0.7, 1"
2632
StableRNGs = "1.0"
33+
Test = "1"
34+
Tulip = "0.9"
2735
julia = "1.5"
2836

2937
[extras]
3038
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
3139
Clarabel = "61c947e1-3e6d-4ee4-985a-eec8c727bd6e"
40+
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
3241
GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
42+
JSONFBCModels = "475c1105-d6ed-49c1-9b32-c11adca6d3e8"
43+
SBMLFBCModels = "3e8f9d1a-ffc1-486d-82d6-6c7276635980"
44+
SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce"
3345
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
3446
Tulip = "6dd1b50a-3aae-11e9-10b5-ef983d2400fa"
3547

3648
[targets]
37-
test = ["Aqua", "Clarabel", "GLPK", "Test", "Tulip"]
49+
test = ["Aqua", "Clarabel", "Downloads", "GLPK", "SHA", "Test", "Tulip", "JSONFBCModels"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ download("http://bigg.ucsd.edu/static/models/e_coli_core.xml", "e_coli_core.xml"
115115
model = load_model("e_coli_core.xml")
116116

117117
# run a FBA
118-
fluxes = flux_balance_analysis_dict(model, Tulip.Optimizer)
118+
fluxes = flux_balance_dict(model, Tulip.Optimizer)
119119
```
120120

121121
The variable `fluxes` will now contain a dictionary of the computed optimal

docs/Project.toml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
[deps]
2+
AbstractFBCModels = "5a4f3dfa-1789-40f8-8221-69268c29937c"
23
COBREXA = "babc4406-5200-4a30-9033-bf5ae714c842"
3-
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
44
Clarabel = "61c947e1-3e6d-4ee4-985a-eec8c727bd6e"
5-
Clustering = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5"
6-
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
75
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
8-
Escher = "8cc96de1-1b23-48cb-9272-618d67962629"
9-
GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
106
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
11-
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
12-
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
7+
JSONFBCModels = "475c1105-d6ed-49c1-9b32-c11adca6d3e8"
138
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
149
Tulip = "6dd1b50a-3aae-11e9-10b5-ef983d2400fa"
1510

docs/make.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ find_mds(path) =
2525
filter(x -> endswith(x, ".md"), readdir(joinpath(@__DIR__, "src", path))),
2626
)
2727

28+
#TODO migrate this to Documenter-1, and make all checks strict
2829
# build the docs
2930
makedocs(
3031
modules = [COBREXA],
@@ -51,10 +52,11 @@ makedocs(
5152
"Contents" => "concepts.md"
5253
find_mds("concepts")
5354
],
54-
"Reference" => [
55-
"Contents" => "reference.md"
56-
find_mds("reference")
57-
],
55+
"Reference" => "reference.md",
56+
#[ # TODO re-add this when the reference gets bigger
57+
#"Contents" => "reference.md"
58+
#find_mds("reference")
59+
#],
5860
],
5961
)
6062

docs/src/concepts/1_screen.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ screen_variants(
2424
[with_changed_bound("O2t", lb = 0, ub = 0)], # disable O2 transport
2525
[with_changed_bound("CO2t", lb = 0, ub = 0), with_changed_bound("O2t", lb = 0, ub = 0)], # disable both transports
2626
],
27-
m -> flux_balance_analysis_dict(m, Tulip.Optimizer)["BIOMASS_Ecoli_core_w_GAM"],
27+
m -> flux_balance_dict(m, Tulip.Optimizer)["BIOMASS_Ecoli_core_w_GAM"],
2828
)
2929
```
3030
The call specifies a model (the `m` that we have loaded) that is being tested,
@@ -89,7 +89,7 @@ res = screen_variants(m,
8989
["EX_h2o_e", "EX_co2_e", "EX_o2_e", "EX_nh4_e"], # and this set of exchanges
9090
)
9191
],
92-
m -> flux_balance_analysis_dict(m, Tulip.Optimizer)["BIOMASS_Ecoli_core_w_GAM"],
92+
m -> flux_balance_dict(m, Tulip.Optimizer)["BIOMASS_Ecoli_core_w_GAM"],
9393
)
9494
```
9595

@@ -199,7 +199,7 @@ screen_variants(
199199
[with_disabled_oxygen_transport],
200200
[with_disabled_reaction("NH4t")],
201201
],
202-
m -> flux_balance_analysis_dict(m, Tulip.Optimizer)["BIOMASS_Ecoli_core_w_GAM"],
202+
m -> flux_balance_dict(m, Tulip.Optimizer)["BIOMASS_Ecoli_core_w_GAM"],
203203
)
204204
```
205205

@@ -222,7 +222,7 @@ That should get you the results for all new variants of the model:
222222

223223
Some analysis functions may take additional arguments, which you might want to
224224
vary for the analysis. `modifications` argument of
225-
[`flux_balance_analysis_dict`](@ref) is one example of such argument, allowing
225+
[`flux_balance_dict`](@ref) is one example of such argument, allowing
226226
you to specify details of the optimization procedure.
227227

228228
[`screen`](@ref) function allows you to do precisely that -- apart from
@@ -242,7 +242,7 @@ iterations needed for Tulip solver to find a feasible solution:
242242
screen(m,
243243
args = [(i,) for i in 5:15], # the iteration counts, packed in 1-tuples
244244
analysis = (m,a) -> # `args` elements get passed as the extra parameter here
245-
flux_balance_analysis_vec(m,
245+
flux_balance_vec(m,
246246
Tulip.Optimizer;
247247
modifications=[modify_optimizer_attribute("IPM_IterationsLimit", a)],
248248
),

docs/src/examples/01-loading-and-saving.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
using COBREXA
55

66
# TODO: download the models into a single directory that can get cached. Probably best have a fake mktempdir().
7+
#
8+
# TODO: demonstrate download_model here and explain how to get hashes (simply not fill them in for the first time)
Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,51 @@
11

2-
# # Flux balance analysis
2+
# # Flux balance analysis (FBA)
3+
4+
# Here we use [`flux_balance`](@ref) and several related functions to
5+
# find an optimal flux in the *E. coli* "core" model. We will need the model,
6+
# which we can download using [`download_model`](@ref):
37

48
using COBREXA
59

6-
# TODO: run FBA on a FBC model
10+
download_model(
11+
"http://bigg.ucsd.edu/static/models/e_coli_core.json",
12+
"e_coli_core.json",
13+
"7bedec10576cfe935b19218dc881f3fb14f890a1871448fc19a9b4ee15b448d8",
14+
)
15+
16+
# Additionally to COBREXA and the model format package, we will need a solver
17+
# -- let's use Tulip here:
18+
19+
import JSONFBCModels
20+
import Tulip
21+
22+
model = load_model("e_coli_core.json")
23+
24+
# ## Running a FBA
25+
#
26+
# There are many possibilities on how to arrange the metabolic model into the
27+
# optimization framework and how to actually solve it. The "usual" assumed one
28+
# is captured in the default behavior of function
29+
# [`flux_balance`](@ref):
30+
31+
solution = flux_balance(model, Tulip.Optimizer)
32+
33+
@test isapprox(solution.objective, 0.8739, atol = TEST_TOLERANCE) #src
34+
35+
# The result contains a tree of all optimized values in the model, including
36+
# fluxes, the objective value, and possibly others (given by what the model
37+
# contains).
38+
#
39+
# You can explore the dot notation to explore the solution, extracting e.g. the
40+
# value of the objective:
41+
42+
solution.objective
43+
44+
# ...or the value of the flux through the given reaction (note the solution is
45+
# not unique in FBA):
46+
47+
solution.fluxes.PFK
48+
49+
# ...or make a "table" of all fluxes through all reactions:
50+
51+
collect(solution.fluxes)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
# # Changing optimizer parameters
3+
#
4+
# Many optimizers require fine-tuning to produce best results. You can pass in
5+
# additional optimizer settings via the `modifications` parameter of
6+
# [`flux_balance`](@ref). These include e.g.
7+
#
8+
# - [`set_optimizer_attribute`](@ref) (typically allowing you to tune e.g.
9+
# iteration limits, tolerances, or floating-point precision)
10+
# - [`set_objective_sense`](@ref) (allowing you to change and reverse the
11+
# optimization direction, if required)
12+
# - [`silence`](@ref) to disable the debug output of the optimizer
13+
# - and even [`set_optimizer`](@ref), which changes the optimizer
14+
# implementation used (this is not quite useful in this case, but becomes
15+
# beneficial with more complex, multi-stage optimization problems)
16+
#
17+
# To demonstrate this, we'll use the usual toy model:
18+
19+
using COBREXA
20+
import JSONFBCModels, Tulip
21+
22+
download_model(
23+
"http://bigg.ucsd.edu/static/models/e_coli_core.json",
24+
"e_coli_core.json",
25+
"7bedec10576cfe935b19218dc881f3fb14f890a1871448fc19a9b4ee15b448d8",
26+
)
27+
28+
model = load_model("e_coli_core.json")
29+
30+
# Running a FBA with a silent optimizer that has slightly increased iteration
31+
# limit for IPM algorithm may now look as follows:
32+
solution = flux_balance(
33+
model,
34+
Tulip.Optimizer;
35+
modifications = [silence, set_optimizer_attribute("IPM_IterationsLimit", 1000)],
36+
)
37+
38+
@test !isnothing(solution) #src
39+
40+
# To see some of the effects of the configuration changes, you may e.g.
41+
# deliberately cripple the optimizer's possibilities to a few iterations, which
42+
# will cause it to fail and return no solution:
43+
44+
solution = flux_balance(
45+
model,
46+
Tulip.Optimizer;
47+
modifications = [silence, set_optimizer_attribute("IPM_IterationsLimit", 2)],
48+
)
49+
50+
println(solution)
51+
52+
@test isnothing(solution) #src
53+
54+
# Applicable optimizer attributes are documented in the documentations of the
55+
# respective optimizers. To browse the possibilities, you may want to see the
56+
# [JuMP documentation page that summarizes the references to the available
57+
# optimizers](https://jump.dev/JuMP.jl/stable/installation/#Supported-solvers).

0 commit comments

Comments
 (0)