From 0e04a8bb7dccf252df6377edb0e6e3af6c9364bc Mon Sep 17 00:00:00 2001 From: stelmo <stelmozors@gmail.com> Date: Thu, 1 Apr 2021 14:47:49 +0200 Subject: [PATCH] added constraint modification callback --- src/analysis/fba.jl | 95 ++++++++++++++++++++++++++++++------------- src/base/utilities.jl | 60 --------------------------- 2 files changed, 66 insertions(+), 89 deletions(-) diff --git a/src/analysis/fba.jl b/src/analysis/fba.jl index ad8a5c748..7b9beed1e 100644 --- a/src/analysis/fba.jl +++ b/src/analysis/fba.jl @@ -22,9 +22,10 @@ Arguments are passed to [`flux_balance_analysis`](@ref). """ function flux_balance_analysis_vec(args...)::Union{Vector{Float64},Nothing} optmodel = flux_balance_analysis(args...) - + vars = optmodel[:x] + termination_status(optmodel) in [MOI.OPTIMAL, MOI.LOCALLY_SOLVED] || return nothing - value.(optmodel[:x]) + value.(vars) end """ @@ -43,7 +44,7 @@ function flux_balance_analysis_dict( end """ - flux_balance_analysis(model::CobraModel, optimizer; objective_func::Union{Reaction, Array{Reaction, 1}}=Reaction[], weights=Float64[], solver_attributes=Dict{Any, Any}(), constraints=Dict{String, Tuple{Float64,Float64}}()) + fba(model::CobraModel, optimizer; objective_func::Union{Reaction, Array{Reaction, 1}}=Reaction[], weights=Float64[], solver_attributes=Dict{Any, Any}(), constraints=Dict{String, Tuple{Float64,Float64}}()) Run flux balance analysis (FBA) on the `model` optionally specifying `objective_rxn(s)` and their `weights` (empty `weights` mean equal weighting per reaction). Optionally also specify any additional flux constraints with `constraints`, a dictionary mapping reaction `id`s to tuples of (lb, ub) flux constraints. @@ -61,40 +62,76 @@ biomass = findfirst(model.reactions, "BIOMASS_Ec_iJO1366_WT_53p95M") sol = fba(model, biomass, optimizer; solver_attributes=atts) ``` """ -function flux_balance_analysis( +function fba( model::CobraModel, optimizer; - modifications::Union{Vector, Function} = [(model, opt_model)->nothing] + modifications = [(model, opt_model)->nothing] ) + +objective_func::Union{Reaction,Array{Reaction,1}} = Reaction[] +weights = Float64[] +solver_attributes = Dict{Any,Any}() +sense = MOI.MAX_SENSE + # get core optimization problem - cbm = make_optimization_model(model, optimizer) - - # apply callbacks - user can also just put in a function - if typeof(modifications) <: Vector - for mod in modifications - mod(model, cbm) - end - else - modifications(model, cbm) + cbm = make_optimization_model(model, optimizer, sense = sense) + v = cbm[:x] # fluxes + + # apply callbacks + for mod in modifications + mod(model, cbm) end - optimize!(cbm) - - return cbm -end + # modify core optimization problem according to user specifications + if !isempty(solver_attributes) # set other attributes + for (k, val) in solver_attributes + set_optimizer_attribute(cbm, k, val) + end + end -function flux_balance_analysis_vec() + # if an objective function is supplied, modify the default objective + if typeof(objective_func) == Reaction || !isempty(objective_func) + # ensure that an array of objective indices are fed in + if typeof(objective_func) == Reaction + objective_indices = [model[objective_func]] + else + objective_indices = [model[rxn] for rxn in objective_func] + end -end + if isempty(weights) + weights = ones(length(objective_indices)) + end + opt_weights = zeros(length(model.reactions)) -status = ( - termination_status(cbm) == MOI.OPTIMAL || - termination_status(cbm) == MOI.LOCALLY_SOLVED -) + # update the objective function tracker + # don't update model objective function - silly thing to do + wcounter = 1 + for i in eachindex(model.reactions) + if i in objective_indices + # model.reactions[i].objective_coefficient = weights[wcounter] + opt_weights[i] = weights[wcounter] + wcounter += 1 + # else + # model.reactions[i].objective_coefficient = 0.0 + end + end + + @objective(cbm, sense, sum(opt_weights[i] * v[i] for i in objective_indices)) + else # use default objective + # automatically assigned by make_optimization_model + end + + optimize!(cbm) + + status = ( + termination_status(cbm) == MOI.OPTIMAL || + termination_status(cbm) == MOI.LOCALLY_SOLVED + ) -if status - return map_fluxes(cbm[:v], model) -else - @warn "Optimization issues occurred." - return Dict{String,Float64}() + if status + return map_fluxes(v, model) + else + @warn "Optimization issues occurred." + return Dict{String,Float64}() + end end diff --git a/src/base/utilities.jl b/src/base/utilities.jl index 0ae3f14c9..e2d6d7233 100644 --- a/src/base/utilities.jl +++ b/src/base/utilities.jl @@ -46,63 +46,3 @@ function modify_constraint(reaction::Reaction, lb, ub) set_bound(ind, opt_model, lb=lb, ub=ub) end end - -""" - modify_sense(sense) - - Modify the objective sense. -Allowed options are MOI.MAX_SENSE and MOI.MIN_SENSE. -""" -function modify_sense(sense) - (model, opt_model) -> begin - set_objective_sense(opt_model, sense) - end -end - -""" -modify_solver_attributes(option_key, option_value) - -""" -function modify_solver_attributes(option_key, option_value) - (model, opt_model) -> begin - set_optimizer_attribute(opt_model, option_key, option_value) - end -end - -""" - modify_objective(objective_function::Union{Reaction,Array{Reaction,1}}; objective_weights=[], sense=MOI.MAX_SENSE) - -Modify the objective function and optionally specify weights -(useful if more than one reaction is set in `objective_rxns`) -and the sense of the objective. - -# Example -""" -function modify_objective(objective_function::Union{Reaction,Array{Reaction,1}}; objective_weights=[], sense=MOI.MAX_SENSE) - (model, opt_model) -> begin - v = opt_model[:x] - - # ensure that an array of objective indices are fed in - if typeof(objective_function) == Reaction - objective_indices = [model[objective_function]] - else - objective_indices = [model[rxn] for rxn in objective_function] - end - - if isempty(objective_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 - - @objective(cbm, MOI.MAX_SENSE, sum(opt_weights[i] * v[i] for i in objective_indices)) - end -end -- GitLab