opencobra / cobrapy

COBRApy is a package for constraint-based modeling of metabolic networks.
http://opencobra.github.io/cobrapy/
GNU General Public License v2.0
457 stars 212 forks source link

ContainerAlreadyContains error when doing an optimization with cobra #1026

Closed WackerO closed 3 years ago

WackerO commented 3 years ago

I am trying to run an optimization with cobra to create a coop-medium for two organisms. For this, I set up constraints and objectives like it was explained in the docu. Sadly, my code produces a ContainerAlreadyContains error, and I have no idea where it comes from; an internet search did not help. I was understanding that my newly defined constraints would be added to those already in the model or maybe they would overwrite the old constraints if affecting the same component, or is this incorrect?

I am using two other models, but managed to produce the same error with the cobra testmodel with the code posted below. Using python 3.7.0 and cobra 0.19.0. Hopefully someone can help me; thanks in any case!

import cobra
import copy
import cobra.test

def optimize_model(inmodel, medium, biomass, verbose=False):
    model = copy.deepcopy(inmodel)
    metabolites = list(medium.keys())
    reactions = [r.id for r in model.reactions]

    #variables
    thetas = {}
    for m in metabolites:
        var = model.problem.Variable(name="theta_{}".format(m), lb=0, type="binary")
        thetas["theta_{}".format(m)] = var

    #constraints
    constraints = []
    for m in metabolites:
        try:
            const = model.problem.Constraint(model.reactions.get_by_id(m).flux_expression + 
                               model.reactions.get_by_id(m).lower_bound*thetas["theta_"+m],
                                lb=model.reactions.get_by_id(m).lower_bound,
                                 name="V_COOPM_{}".format(m))
            constraints.add_cons_vars(const)
        except:
            pass       
    VBM_COMPM = model.optimize().objective_value / 10
    cost = model.problem.Constraint(biomass.flux_expression, lb=VBM_COMPM)
    constraints.append(cost)

    #objective
    obj = model.problem.Objective(sum(thetas[t] for t in thetas.keys()),
                    direction="max")

    model.add_cons_vars(constraints)
    model.objective = obj
    model.solver.update()
    status = model.optimize()

medium = {
    'EX_ala__L_e': 'Alanine', 'EX_arg__L_e': 'Arginine',
    'EX_cys__L_e': 'Cysteine', 'EX_glu__L_e': 'Glutamic acid',
    'EX_gly_e': 'Glycine', 'EX_his__L_e': 'Histidine',
    'EX_leu__L_e': 'Leucine', 'EX_lys__L_e': 'Lysine', 'EX_orn_e': 'Ornithine',
    'EX_phe__L_e': 'Phenylalanine', 'EX_pro__L_e': 'Proline',
    'EX_ser__L_e': 'Serine', 'EX_thr__L_e': 'Threonine',
    'EX_trp__L_e': 'Tryptophane', 'EX_val__L_e': 'Valine',
    'EX_cit_e': 'citric acid', 'EX_fum_e': 'Fumaric acid',
    'EX_male_e': 'maleic acid', 'EX_pyr_e': 'pyruvic acid',
    'EX_succ_e': 'succinic acid', 'EX_glc__D_e': 'glucose',
    'EX_urea_e': 'Urea', 'EX_na1_e': 'Sodium', 'EX_cl_e': 'Chloride',
    'EX_k_e': 'Potassium', 'EX_pi_e': 'Phosphate', 'EX_mg2_e': 'Magnesium',
    'EX_so4_e': 'Sulphate', 'EX_ca2_e': 'Calcium', 'EX_zn2_e': 'ZnCl2',
    'EX_mn2_e': 'MnCl2', 'EX_cobalt2_e': 'CoCl2', 'EX_cu2_e': 'CuCl2',
    'EX_ni2_e': 'NiCl2', 'EX_mobd_e': 'MoNa2O4', 'EX_adocbl_e': 'Cyanocobalamine',
    'EX_4abz_e': 'p-Aminobenzoic acid', 'EX_btn_e': 'Biotin', 'EX_nac_e': 'Nicotinic acid',
    'EX_pnto__R_e': 'Ca-D-Pantothenic acid', 'EX_pydam_e': 'Pyridoxamine-2HCl',
    'EX_thm_e': 'Thiamine-dichloride', 'EX_ribflv_e': 'Riboflavin', 'EX_o2_e': 'Oxygen',
    'EX_fe2_e': 'Fe3+', 'EX_h2o_e': 'Water', 'EX_co2_e': 'Co2'
}

model = cobra.test.create_test_model("textbook")
for r in model.reactions:
    if r.id == "Biomass_Ecoli_core":
        biomass = r
        break
optimize_model(model, medium, biomass, True)
cdiener commented 3 years ago

There are a few things going on, so let me go through them.

  1. The error you see comes from setting the cost constraint. This is due to using variables from the original model in a constraint set on the copied model. The copied model now has its own set of variables different from the old model but with the same name (the copies of the variables). Your cost constraint used variables from the old model. Cobrapy detects that those variables are not part of the model yet and tries to add them automatically but ultimately fails since the model already contains the new copied variables with the same name. you can avoid that by directly getting the flux expression for the Biomass constraint from the copied/new model: cost = model.problem.Constraint(model.reactions.get_by_id("Biomass_Ecoli_core").flux_expression, lb=VBM_COMPM).

  2. In the try-except block constraints is a list and lists have no method add_cons_vars so this will always throw an error and will always jump to the except block. I think you meant constraints.append(const).

  3. The optimize_model function returns nothing.

WackerO commented 3 years ago

That did the trick, thank you so much!