Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added loopless fba #60

Merged
merged 7 commits into from
Apr 12, 2021
Merged

Added loopless fba #60

merged 7 commits into from
Apr 12, 2021

Conversation

marvinvanaalst
Copy link
Collaborator

Added loopless FBA

Two interfaces:

  • loopless, to do the FBA and loopless FBA after each other
  • loopless_solution to work on an existing FBA solution

It should be straight-forward to replace parts of the functionality, as most of it was pulled out into separate functions. This should make merging it with other developments in the FBA routine easier, since it heavily depends on it

Copy link
Collaborator

@stelmo stelmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, and thanks for adding in tests!

src/analysis/looplessfba.jl Outdated Show resolved Hide resolved
Copy link
Collaborator

@stelmo stelmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments :)


# Is there a way to get the objective indices if we set the
# objective via `change_objective`? then we could recycle the flux_balance_analysis
# method in a better way
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, JumP.objective_function, look at line 37 of parimonious_flux_balance_analysis.jl for a use case.

Comment on lines 123 to 124
objective_func::Union{Reaction,Array{Reaction,1}},
weights=[],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be wrapped into the modifications? Ideally all the analysis functions would have the same arguments where possible

Comment on lines 134 to 136
objective_indices = _get_reaction_indices(model, objective_func)
opt_weights = _get_objective_weights(model, objective_indices, weights)
change_objective(objective_func, weights=weights)(model, opt_model)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is necessary if you have the callbacks.

Comment on lines 5 to 11
function _set_solver_attibutes!(opt_model, solver_attributes)
if !isempty(solver_attributes) # set other attributes
for (k, val) in solver_attributes
set_optimizer_attribute(opt_model, k, val)
end
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already have similar functionality in src/base/utilities.jl as change_solver_attributes.

Comment on lines 13 to 18
function _set_additional_constraints!(model, opt_model, constraints)
for (rxnid, con) in constraints
ind = model.reactions[findfirst(model.reactions, rxnid)]
set_bound(ind, opt_model; lb=con[1], ub=con[2])
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment and change_constraint

Comment on lines 20 to 44
function _get_reaction_indices(model, objective_func)
if typeof(objective_func) == Reaction
objective_indices = [model[objective_func]]
else
objective_indices = [model[rxn] for rxn in objective_func]
end
return objective_indices
end

function _get_objective_weights(model, objective_indices, weights)
if isempty(weights)
weights = ones(length(objective_indices))
end
opt_weights = zeros(length(model.reactions))

# update the objective function tracker
wcounter = 1
for i in eachindex(model.reactions)
if i in objective_indices
opt_weights[i] = weights[wcounter]
wcounter += 1
end
end
return opt_weights
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could probably read this out using JuMP, see comment below.

Comment on lines 46 to 53
function _constrain_objective_value!(opt_model, opt_weights, objective_indices)
λ = objective_value(opt_model)
v = opt_model[:x]
@constraint(
opt_model,
λ <= sum(opt_weights[i] * v[i] for i in objective_indices) <= λ
)
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if necessary to make this a function. Also look at parsimonious_flux_balance_analysis.jl to see how to make this more robust, specifically lines 51 - 58.

Comment on lines 97 to 98
opt_weights,
objective_indices,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hopefully not necessary after comments

Comment on lines 152 to 158
return loopless_solution(
model,
opt_model,
opt_weights,
objective_indices,
fluxes,
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Collaborator

@stelmo stelmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! Just a couple of tiny changes and then it'll be ready :)

COBREXA.JuMP.termination_status(opt_model) in [MOI.OPTIMAL, MOI.LOCALLY_SOLVED] ||
return nothing
return Dict(zip(reactions(model), value.(opt_model[:x])))
function add_loopless(model::M, opt_model, fluxes::Dict{String,Float64})::JuMP.Model where {M <: MetabolicModel}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need COBREXA.JuMP.Model here

Comment on lines 83 to 93
"""
loopless_solution(args...)::Union{Dict{String,Float64},Nothing}

Convert an existing FBA solution to a loopless one. Removes as many loops as possible usingthe method from [1]

References:
[1] CycleFreeFlux: efficient removal of thermodynamically infeasible
loops from flux distributions. Desouki AA, Jarre F, Gelius-Dietrich
G, Lercher MJ. Bioinformatics. 2015 Jul 1;31(13):2159-65. doi:
10.1093/bioinformatics/btv096.
"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get rid of this!

Comment on lines 5 to 12
function constrain_objective_value()
return (model, opt_model) -> begin
λ = objective_value(opt_model)
old_objective = objective_function(opt_model)
@constraint(
opt_model,
λ <= sum(old_objective) <= λ
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move this to src/utilities.jl since it is now a callback, it could maybe be used in other functions. But give it an optimum_bound argument so that I can directly use it in src/analysis/flux_variability_analysis.jl on line 159 - 166 :)

@exaexa
Copy link
Collaborator

exaexa commented Apr 9, 2021

Ey,

can we separate out the "fixes" of CobraModel to StandardModel in docs/ and merge them separately?

In particular, I'm doing that in parallel now, so I was kinda expected to see the conflict here :]

Otherwise it looks cool, will give it a deeper dive later today

@laurentheirendt
Copy link
Member

@marvinvanaalst and @exaexa can we wrap this up?

Copy link
Collaborator

@exaexa exaexa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 from me (if the formatting doesn't trigger formatcheck failure)

EDIT: apparently it doesn't trigger any failure, feel free to merge. I'll eventually move my cleaning monsterpullrequest onto this.

@@ -97,7 +97,7 @@ function flux_balance_analysis_dict(
model::M,
args...;
kwargs...,
)::Union{Dict{String,Float64},Nothing} where {M<:MetabolicModel}
)::Union{Dict{String,Float64},Nothing} where {M <: MetabolicModel}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might cause a tiny problem later, Formatter formats the typenames without spaces around <: for me. Does this come from the formatter?

G, Lercher MJ. Bioinformatics. 2015 Jul 1;31(13):2159-65. doi:
10.1093/bioinformatics/btv096.
"""
function add_loopless_vec(model::M, opt_model, fluxes::Dict{String,Float64})::Union{Array{Float64,1},Nothing} where {M <: MetabolicModel}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks nice, I'll see if we can unify the code with the main FBA later.

top_n = 8,
ignorebound = 1000.0,
verbose = true,
top_n=8,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this from JuliaFormatter?

@laurentheirendt laurentheirendt merged commit 573b868 into master Apr 12, 2021
@laurentheirendt laurentheirendt deleted the mva-loopless-fba branch April 12, 2021 07:13
exaexa pushed a commit that referenced this pull request Jul 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants