def test_change_coefficient(self, solver_test): solver, old_solution, infeasible_model = solver_test c = Metabolite("c") c._bound = 6 x = Reaction("x") x.lower_bound = 1. y = Reaction("y") y.lower_bound = 0. x.add_metabolites({c: 1}) z = Reaction("z") z.add_metabolites({c: 1}) z.objective_coefficient = 1 m = Model("test_model") m.add_reactions([x, y, z]) # change an existing coefficient lp = solver.create_problem(m) solver.solve_problem(lp) sol1 = solver.format_solution(lp, m) assert sol1.status == "optimal" solver.change_coefficient(lp, 0, 0, 2) solver.solve_problem(lp) sol2 = solver.format_solution(lp, m) assert sol2.status == "optimal" assert abs(sol1.f - 5.0) < 10 ** -3 assert abs(sol2.f - 4.0) < 10 ** -3 # change a new coefficient z.objective_coefficient = 0. y.objective_coefficient = 1. lp = solver.create_problem(m) solver.change_coefficient(lp, 0, 1, 2) solver.solve_problem(lp) solution = solver.format_solution(lp, m) assert solution.status == "optimal" assert abs(solution.x_dict["y"] - 2.5) < 10 ** -3
def test_complicated_model(self): """Difficult model since the online mean calculation is numerically unstable so many samples weakly violate the equality constraints.""" model = Model('flux_split') reaction1 = Reaction('V1') reaction2 = Reaction('V2') reaction3 = Reaction('V3') reaction1.lower_bound = 0 reaction2.lower_bound = 0 reaction3.lower_bound = 0 reaction1.upper_bound = 6 reaction2.upper_bound = 8 reaction3.upper_bound = 10 A = Metabolite('A') reaction1.add_metabolites({A: -1}) reaction2.add_metabolites({A: -1}) reaction3.add_metabolites({A: 1}) model.add_reactions([reaction1]) model.add_reactions([reaction2]) model.add_reactions([reaction3]) optgp = OptGPSampler(model, 1, seed=42) achr = ACHRSampler(model, seed=42) optgp_samples = optgp.sample(100) achr_samples = achr.sample(100) assert any(optgp_samples.corr().abs() < 1.0) assert any(achr_samples.corr().abs() < 1.0) # > 95% are valid assert(sum(optgp.validate(optgp_samples) == "v") > 95) assert(sum(achr.validate(achr_samples) == "v") > 95)
def test_add_reactions(self, model): r1 = Reaction('r1') r1.add_metabolites({Metabolite('A'): -1, Metabolite('B'): 1}) r1.lower_bound, r1.upper_bound = -999999., 999999. r2 = Reaction('r2') r2.add_metabolites({ Metabolite('A'): -1, Metabolite('C'): 1, Metabolite('D'): 1 }) r2.lower_bound, r2.upper_bound = 0., 999999. model.add_reactions([r1, r2]) r2.objective_coefficient = 3. assert r2.objective_coefficient == 3. assert model.reactions[-2] == r1 assert model.reactions[-1] == r2 assert isinstance(model.reactions[-2].reverse_variable, model.problem.Variable) coefficients_dict = model.objective.expression. \ as_coefficients_dict() biomass_r = model.reactions.get_by_id('Biomass_Ecoli_core') assert coefficients_dict[biomass_r.forward_variable] == 1. assert coefficients_dict[biomass_r.reverse_variable] == -1. assert coefficients_dict[model.reactions.r2.forward_variable] == 3. assert coefficients_dict[model.reactions.r2.reverse_variable] == -3.
def test_solve_mip(self, solver_test): solver, old_solution, infeasible_model = solver_test if not hasattr(solver, "_SUPPORTS_MILP") or not solver._SUPPORTS_MILP: pytest.skip("no milp support") cobra_model = Model('MILP_implementation_test') constraint = Metabolite("constraint") constraint._bound = 2.5 x = Reaction("x") x.lower_bound = 0. x.objective_coefficient = 1. x.add_metabolites({constraint: 2.5}) y = Reaction("y") y.lower_bound = 0. y.objective_coefficient = 1. y.add_metabolites({constraint: 1.}) cobra_model.add_reactions([x, y]) float_sol = solver.solve(cobra_model) # add an integer constraint y.variable_kind = "integer" int_sol = solver.solve(cobra_model) assert abs(float_sol.f - 2.5) < 10 ** -5 assert abs(float_sol.x_dict["y"] - 2.5) < 10 ** -5 assert int_sol.status == "optimal" assert abs(int_sol.f - 2.2) < 10 ** -3 assert abs(int_sol.x_dict["y"] - 2.0) < 10 ** -3
def test_inequality(self, solver_test): solver, old_solution, infeasible_model = solver_test # The space enclosed by the constraints is a 2D triangle with # vertexes as (3, 0), (1, 2), and (0, 1) # c1 encodes y - x > 1 ==> y > x - 1 # c2 encodes y + x < 3 ==> y < 3 - x c1 = Metabolite("c1") c2 = Metabolite("c2") x = Reaction("x") x.lower_bound = 0 y = Reaction("y") y.lower_bound = 0 x.add_metabolites({c1: -1, c2: 1}) y.add_metabolites({c1: 1, c2: 1}) c1._bound = 1 c1._constraint_sense = "G" c2._bound = 3 c2._constraint_sense = "L" m = Model() m.add_reactions([x, y]) # test that optimal values are at the vertices m.objective = "x" assert abs(solver.solve(m).f - 1.0) < 10 ** -3 assert abs(solver.solve(m).x_dict["y"] - 2.0) < 10 ** -3 m.objective = "y" assert abs(solver.solve(m).f - 3.0) < 10 ** -3 assert abs( solver.solve(m, objective_sense="minimize").f - 1.0) < 10 ** -3
def test_complicated_model(self): """Difficult model since the online mean calculation is numerically unstable so many samples weakly violate the equality constraints.""" model = Model('flux_split') reaction1 = Reaction('V1') reaction2 = Reaction('V2') reaction3 = Reaction('V3') reaction1.lower_bound = 0 reaction2.lower_bound = 0 reaction3.lower_bound = 0 reaction1.upper_bound = 6 reaction2.upper_bound = 8 reaction3.upper_bound = 10 A = Metabolite('A') reaction1.add_metabolites({A: -1}) reaction2.add_metabolites({A: -1}) reaction3.add_metabolites({A: 1}) model.add_reactions([reaction1]) model.add_reactions([reaction2]) model.add_reactions([reaction3]) optgp = OptGPSampler(model, 1, seed=42) achr = ACHRSampler(model, seed=42) optgp_samples = optgp.sample(100) achr_samples = achr.sample(100) assert any(optgp_samples.corr().abs() < 1.0) assert any(achr_samples.corr().abs() < 1.0) # > 95% are valid assert (sum(optgp.validate(optgp_samples) == "v") > 95) assert (sum(achr.validate(achr_samples) == "v") > 95)
def test_quadratic(self, solver_test): solver, old_solution, infeasible_model = solver_test if not hasattr(solver, "set_quadratic_objective"): pytest.skip("no qp support") c = Metabolite("c") c._bound = 2 x = Reaction("x") x.objective_coefficient = -0.5 x.lower_bound = 0. y = Reaction("y") y.objective_coefficient = -0.5 y.lower_bound = 0. x.add_metabolites({c: 1}) y.add_metabolites({c: 1}) m = Model() m.add_reactions([x, y]) lp = solver.create_problem(m) quadratic_obj = scipy.sparse.eye(2) * 2 solver.set_quadratic_objective(lp, quadratic_obj) solver.solve_problem(lp, objective_sense="minimize") solution = solver.format_solution(lp, m) assert solution.status == "optimal" # Respecting linear objectives also makes the objective value 1. assert abs(solution.f - 1.) < 10 ** -3 assert abs(solution.x_dict["y"] - 1.) < 10 ** -3 assert abs(solution.x_dict["y"] - 1.) < 10 ** -3 # When the linear objectives are removed the objective value is 2. solver.change_variable_objective(lp, 0, 0.) solver.change_variable_objective(lp, 1, 0.) solver.solve_problem(lp, objective_sense="minimize") solution = solver.format_solution(lp, m) assert solution.status == "optimal" assert abs(solution.f - 2.) < 10 ** -3 # test quadratic from solve function solution = solver.solve(m, quadratic_component=quadratic_obj, objective_sense="minimize") assert solution.status == "optimal" assert abs(solution.f - 1.) < 10 ** -3 c._bound = 6 z = Reaction("z") x.objective_coefficient = 0. y.objective_coefficient = 0. z.lower_bound = 0. z.add_metabolites({c: 1}) m.add_reaction(z) solution = solver.solve(m, quadratic_component=scipy.sparse.eye(3), objective_sense="minimize") # should be 12 not 24 because 1/2 (V^T Q V) assert solution.status == "optimal" assert abs(solution.f - 6) < 10 ** -3 assert abs(solution.x_dict["x"] - 2) < 10 ** -6 assert abs(solution.x_dict["y"] - 2) < 10 ** -6 assert abs(solution.x_dict["z"] - 2) < 10 ** -6
def constrainSumOfFluxes(cobra_model, rxn2avoid, SFvalue, objvalue): from cobra.core import Metabolite, Reaction temp = cobra_model.copy() SFMet = Metabolite("SFMet", name="Sum of fluxes pseudometabolite", compartment="c2") for rxn in cobra_model.reactions: if not rxn2avoid.__contains__(rxn.id): if rxn.id.__contains__("reverse"): temp.reactions.get_by_id(rxn.id).add_metabolites({SFMet: -1}) else: temp.reactions.get_by_id(rxn.id).add_metabolites({SFMet: 1}) SFRxn = Reaction("SFRxn", name="Sum of fluxes pseudoreaction") SFRxn.add_metabolites({SFMet: -1}) SFRxn.lower_bound = SFvalue SFRxn.upper_bound = SFvalue temp.add_reaction(SFRxn) if (not objvalue == "") and (len( [rxn for rxn in temp.reactions if rxn.objective_coefficient == 1]) == 1): for rxn in [ rxn for rxn in temp.reactions if rxn.objective_coefficient == 1 ]: rxn.lower_bound = float(objvalue) rxn.upper_bound = float(objvalue) return temp
def test__normalize_pseudoreaction_demand(): reaction = Reaction('DM_gone') reaction.add_metabolites({Metabolite('glu__L_c'): -1}) reaction.lower_bound = 0 reaction.upper_bound = 1000 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert pseudo_id == 'DM_glu__L_c' assert reaction.subsystem == 'Intracellular demand'
def test__normalize_pseudoreaction_exchange(): reaction = Reaction('EX_gone') reaction.add_metabolites({Metabolite('glu__L_e'): -1}) reaction.lower_bound = -1000 reaction.upper_bound = 0 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert pseudo_id == 'EX_glu__L_e' assert reaction.subsystem == 'Extracellular exchange'
def test__normalize_pseudoreaction_sink(): reaction = Reaction('SInk_gone') reaction.add_metabolites({Metabolite('glu__L_c'): -1}) reaction.lower_bound = -1000 reaction.upper_bound = 0 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert pseudo_id == 'SK_glu__L_c' assert reaction.subsystem == 'Intracellular source/sink'
def test_add_reactions_single_existing(model): rxn = model.reactions[0] r1 = Reaction(rxn.id) r1.add_metabolites({Metabolite("A"): -1, Metabolite("B"): 1}) r1.lower_bound, r1.upper_bound = -999999.0, 999999.0 model.add_reactions([r1]) assert rxn in model.reactions assert r1 is not model.reactions.get_by_id(rxn.id)
def test_add_reactions_single_existing(self, model): rxn = model.reactions[0] r1 = Reaction(rxn.id) r1.add_metabolites({Metabolite('A'): -1, Metabolite('B'): 1}) r1.lower_bound, r1.upper_bound = -999999., 999999. model.add_reactions([r1]) assert rxn in model.reactions assert r1 is not model.reactions.get_by_id(rxn.id)
def tiny_toy_model(): model = Model("Toy Model") m1 = Metabolite("M1") d1 = Reaction("ex1") d1.add_metabolites({m1: -1}) d1.upper_bound = 0 d1.lower_bound = -1000 model.add_reactions([d1]) return model
def test__normalize_pseudoreaction_demand_reversed_prefer_sink_name(): reaction = Reaction('sink_gone') reaction.add_metabolites({Metabolite('glu__L_c'): 1}) reaction.lower_bound = -1000 reaction.upper_bound = 0 _normalize_pseudoreaction(reaction) assert list(reaction.metabolites.values()) == [-1] assert reaction.lower_bound == 0 assert reaction.upper_bound == 1000 assert reaction.id == 'SK_glu__L_c'
def test__normalize_pseudoreaction_sink_reversed(): reaction = Reaction('Sink_gone') reaction.add_metabolites({Metabolite('glu__L_c'): 1}) reaction.lower_bound = 0 reaction.upper_bound = 50 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert list(reaction.metabolites.values()) == [-1] assert reaction.lower_bound == -50 assert reaction.upper_bound == 0 assert pseudo_id == 'SK_glu__L_c'
def test__normalize_pseudoreaction_demand_reversed(): reaction = Reaction('DM_gone') reaction.add_metabolites({Metabolite('glu__L_c'): 1}) reaction.lower_bound = -1000 reaction.upper_bound = 0 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert list(reaction.metabolites.values()) == [-1] assert reaction.lower_bound == 0 assert reaction.upper_bound == 1000 assert pseudo_id == 'DM_glu__L_c'
def test__normalize_pseudoreaction_exchange_reversed(): reaction = Reaction('EX_gone') reaction.add_metabolites({Metabolite('glu__L_e'): 1}) reaction.lower_bound = 0 reaction.upper_bound = 1000 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert pseudo_id == 'EX_glu__L_e' assert reaction.lower_bound == -1000 assert reaction.upper_bound == 0 assert list(reaction.metabolites.values()) == [-1]
def construct_loopless_model(cobra_model): """Construct a loopless model. This adds MILP constraints to prevent flux from proceeding in a loop, as done in http://dx.doi.org/10.1016/j.bpj.2010.12.3707 Please see the documentation for an explanation of the algorithm. This must be solved with an MILP capable solver. """ # copy the model and make it irreversible model = cobra_model.copy() convert_to_irreversible(model) max_ub = max(model.reactions.list_attr("upper_bound")) # a dict for storing S^T thermo_stoic = { "thermo_var_" + metabolite.id: {} for metabolite in model.metabolites } # Slice operator is so that we don't get newly added metabolites original_metabolites = model.metabolites[:] for reaction in model.reactions[:]: # Boundary reactions are not subjected to these constraints if len(reaction._metabolites) == 1: continue # populate the S^T dict bound_id = "thermo_bound_" + reaction.id for met, stoic in iteritems(reaction._metabolites): thermo_stoic["thermo_var_" + met.id][bound_id] = stoic # I * 1000 > v --> I * 1000 - v > 0 reaction_ind = Reaction(reaction.id + "_indicator") reaction_ind.variable_kind = "integer" reaction_ind.upper_bound = 1 reaction_ub = Metabolite(reaction.id + "_ind_ub") reaction_ub._constraint_sense = "G" reaction.add_metabolites({reaction_ub: -1}) reaction_ind.add_metabolites({reaction_ub: max_ub}) # This adds a compensating term for 0 flux reactions, so we get # S^T x - (1 - I) * 1001 < -1 which becomes # S^T x < 1000 for 0 flux reactions and # S^T x < -1 for reactions with nonzero flux. reaction_bound = Metabolite(bound_id) reaction_bound._constraint_sense = "L" reaction_bound._bound = max_ub reaction_ind.add_metabolites({reaction_bound: max_ub + 1}) model.add_reaction(reaction_ind) for metabolite in original_metabolites: metabolite_var = Reaction("thermo_var_" + metabolite.id) metabolite_var.lower_bound = -max_ub model.add_reaction(metabolite_var) metabolite_var.add_metabolites({ model.metabolites.get_by_id(k): v for k, v in iteritems(thermo_stoic[metabolite_var.id]) }) return model
def test_add_reactions_duplicate(model): rxn = model.reactions[0] r1 = Reaction('r1') r1.add_metabolites({Metabolite('A'): -1, Metabolite('B'): 1}) r1.lower_bound, r1.upper_bound = -999999., 999999. r2 = Reaction(rxn.id) r2.add_metabolites( {Metabolite('A'): -1, Metabolite('C'): 1, Metabolite('D'): 1}) model.add_reactions([r1, r2]) assert r1 in model.reactions assert rxn in model.reactions assert r2 is not model.reactions.get_by_id(rxn.id)
def test_add_reactions_duplicate(self, model): rxn = model.reactions[0] r1 = Reaction('r1') r1.add_metabolites({Metabolite('A'): -1, Metabolite('B'): 1}) r1.lower_bound, r1.upper_bound = -999999., 999999. r2 = Reaction(rxn.id) r2.add_metabolites( {Metabolite('A'): -1, Metabolite('C'): 1, Metabolite('D'): 1}) model.add_reactions([r1, r2]) assert r1 in model.reactions assert rxn in model.reactions assert r2 is not model.reactions.get_by_id(rxn.id)
def construct_loopless_model(cobra_model): """Construct a loopless model. This adds MILP constraints to prevent flux from proceeding in a loop, as done in http://dx.doi.org/10.1016/j.bpj.2010.12.3707 Please see the documentation for an explanation of the algorithm. This must be solved with an MILP capable solver. """ # copy the model and make it irreversible model = cobra_model.copy() convert_to_irreversible(model) max_ub = max(model.reactions.list_attr("upper_bound")) # a dict for storing S^T thermo_stoic = {"thermo_var_" + metabolite.id: {} for metabolite in model.metabolites} # Slice operator is so that we don't get newly added metabolites original_metabolites = model.metabolites[:] for reaction in model.reactions[:]: # Boundary reactions are not subjected to these constraints if len(reaction._metabolites) == 1: continue # populate the S^T dict bound_id = "thermo_bound_" + reaction.id for met, stoic in iteritems(reaction._metabolites): thermo_stoic["thermo_var_" + met.id][bound_id] = stoic # I * 1000 > v --> I * 1000 - v > 0 reaction_ind = Reaction(reaction.id + "_indicator") reaction_ind.variable_kind = "integer" reaction_ind.upper_bound = 1 reaction_ub = Metabolite(reaction.id + "_ind_ub") reaction_ub._constraint_sense = "G" reaction.add_metabolites({reaction_ub: -1}) reaction_ind.add_metabolites({reaction_ub: max_ub}) # This adds a compensating term for 0 flux reactions, so we get # S^T x - (1 - I) * 1001 < -1 which becomes # S^T x < 1000 for 0 flux reactions and # S^T x < -1 for reactions with nonzero flux. reaction_bound = Metabolite(bound_id) reaction_bound._constraint_sense = "L" reaction_bound._bound = max_ub reaction_ind.add_metabolites({reaction_bound: max_ub + 1}) model.add_reaction(reaction_ind) for metabolite in original_metabolites: metabolite_var = Reaction("thermo_var_" + metabolite.id) metabolite_var.lower_bound = -max_ub model.add_reaction(metabolite_var) metabolite_var.add_metabolites( {model.metabolites.get_by_id(k): v for k, v in iteritems(thermo_stoic[metabolite_var.id])}) return model
def test__normalize_pseudoreaction_atpm_reversed(): reaction = Reaction('notATPM') reaction.add_metabolites({Metabolite('atp_c'): 1, Metabolite('h2o_c'): 1, Metabolite('pi_c'): -1, Metabolite('h_c'): -1, Metabolite('adp_c'): -1}) reaction.lower_bound = -50 reaction.upper_bound = 100 _normalize_pseudoreaction(reaction) assert reaction.id == 'ATPM' assert reaction.lower_bound == -100 assert reaction.upper_bound == 50
def solver_test(request): solver = solvers.solver_dict[request.param] old_solution = 0.8739215 infeasible_model = Model() metabolite_1 = Metabolite("met1") reaction_1 = Reaction("rxn1") reaction_2 = Reaction("rxn2") reaction_1.add_metabolites({metabolite_1: 1}) reaction_2.add_metabolites({metabolite_1: 1}) reaction_1.lower_bound = 1 reaction_2.upper_bound = 2 infeasible_model.add_reactions([reaction_1, reaction_2]) return solver, old_solution, infeasible_model
def test__normalize_pseudoreaction_atpm_reversed(): reaction = Reaction('notATPM') reaction.add_metabolites({Metabolite('atp_c'): 1, Metabolite('h2o_c'): 1, Metabolite('pi_c'): -1, Metabolite('h_c'): -1, Metabolite('adp_c'): -1}) reaction.lower_bound = -50 reaction.upper_bound = 100 pseudo_id = _normalize_pseudoreaction(reaction.id, reaction) assert pseudo_id == 'ATPM' assert reaction.lower_bound == -100 assert reaction.upper_bound == 50
def construct_difference_model(model_1, model_2, norm_type='euclidean'): """Combine two models into a larger model that is designed to calculate differences between the models """ #Get index mappings common_dict = {} #Using copies of the models so things are modified above combined_model = model_1 = model_1.copy() model_2 = model_2.copy() for reaction_1 in model_1.reactions: try: reaction_2 = model_2.reactions.get_by_id(reaction_1.id) common_dict[reaction_1] = reaction_2 except: continue #Add a prefix in front of the mutant_model metabolites and reactions to prevent #name collisions in DictList for the_dict_list in [model_2.metabolites, model_2.reactions]: [setattr(x, 'id', 'mutant_%s'%x.id) for x in the_dict_list] the_dict_list._generate_index() #Update the DictList.dicts combined_model.add_reactions(model_2.reactions) [setattr(x, 'objective_coefficient', 0.) for x in combined_model.reactions] #Add in the difference reactions. The mutant reactions and metabolites are already added. #This must be a list to maintain the correct order when adding the difference_metabolites difference_reactions = [] #Add the difference reactions at the end to speed things up difference_metabolites = [] for reaction_1, reaction_2 in iteritems(common_dict): reaction_1._difference_partner = reaction_2 reaction_2._difference_partner = reaction_1 difference_reaction = Reaction('difference_%s'%reaction_1.id) difference_reactions.append(difference_reaction) difference_reaction.upper_bound = 100000 difference_reaction.lower_bound = -1* difference_reaction.upper_bound difference_metabolite = Metabolite('difference_%s'%reaction_1.id) difference_metabolites.append(difference_metabolite) if norm_type == 'linear': difference_metabolite._constraint_sense = 'G' reaction_1.add_metabolites({difference_metabolite: -1.}, add_to_container_model=False) reaction_2.add_metabolites({difference_metabolite: 1.}, add_to_container_model=False) difference_reaction.add_metabolites({difference_metabolite: 1.}, add_to_container_model=False) combined_model.add_metabolites(difference_metabolites) combined_model.add_reactions(difference_reactions) return(combined_model)
def test_add_reactions_duplicate(model): rxn = model.reactions[0] r1 = Reaction("r1") r1.add_metabolites({Metabolite("A"): -1, Metabolite("B"): 1}) r1.lower_bound, r1.upper_bound = -999999.0, 999999.0 r2 = Reaction(rxn.id) r2.add_metabolites({ Metabolite("A"): -1, Metabolite("C"): 1, Metabolite("D"): 1 }) model.add_reactions([r1, r2]) assert r1 in model.reactions assert rxn in model.reactions assert r2 is not model.reactions.get_by_id(rxn.id)
def test_add_reactions(model): r1 = Reaction("r1") r1.add_metabolites({Metabolite("A"): -1, Metabolite("B"): 1}) r1.lower_bound, r1.upper_bound = -999999.0, 999999.0 r2 = Reaction("r2") r2.add_metabolites({ Metabolite("A"): -1, Metabolite("C"): 1, Metabolite("D"): 1 }) r2.lower_bound, r2.upper_bound = 0.0, 999999.0 model.add_reactions([r1, r2]) r2.objective_coefficient = 3.0 assert r2.objective_coefficient == 3.0 assert model.reactions[-2] == r1 assert model.reactions[-1] == r2 assert isinstance(model.reactions[-2].reverse_variable, model.problem.Variable) coefficients_dict = model.objective.expression.as_coefficients_dict() biomass_r = model.reactions.get_by_id("Biomass_Ecoli_core") assert coefficients_dict[biomass_r.forward_variable] == 1.0 assert coefficients_dict[biomass_r.reverse_variable] == -1.0 assert coefficients_dict[model.reactions.r2.forward_variable] == 3.0 assert coefficients_dict[model.reactions.r2.reverse_variable] == -3.0
def test_add_reactions(self, model): r1 = Reaction('r1') r1.add_metabolites({Metabolite('A'): -1, Metabolite('B'): 1}) r1.lower_bound, r1.upper_bound = -999999., 999999. r2 = Reaction('r2') r2.add_metabolites( {Metabolite('A'): -1, Metabolite('C'): 1, Metabolite('D'): 1}) r2.lower_bound, r2.upper_bound = 0., 999999. model.add_reactions([r1, r2]) r2.objective_coefficient = 3. assert r2.objective_coefficient == 3. assert model.reactions[-2] == r1 assert model.reactions[-1] == r2 assert isinstance(model.reactions[-2].reverse_variable, model.problem.Variable) coefficients_dict = model.objective.expression. \ as_coefficients_dict() biomass_r = model.reactions.get_by_id('Biomass_Ecoli_core') assert coefficients_dict[biomass_r.forward_variable] == 1. assert coefficients_dict[biomass_r.reverse_variable] == -1. assert coefficients_dict[ model.reactions.r2.forward_variable] == 3. assert coefficients_dict[ model.reactions.r2.reverse_variable] == -3.
def test_array_based_model_add(self, model): array_model = model.to_array_based_model() m = len(array_model.metabolites) n = len(array_model.reactions) for matrix_type in ["scipy.dok_matrix", "scipy.lil_matrix"]: test_model = model.copy().to_array_based_model( matrix_type=matrix_type) test_reaction = Reaction("test") test_reaction.add_metabolites({test_model.metabolites[0]: 4}) test_reaction.lower_bound = -3.14 test_model.add_reaction(test_reaction) assert len(test_model.reactions) == n + 1 assert test_model.S.shape == (m, n + 1) assert len(test_model.lower_bounds) == n + 1 assert len(test_model.upper_bounds) == n + 1 assert test_model.S[0, n] == 4 assert test_model.S[7, 0] == -1 assert test_model.lower_bounds[n] == -3.14
def add_reaction(model, id, name, sparse, lower_bound=0, upper_bound=1000): """ Adds a reaction to the model """ # convert the sparse representation using the metabolites in the model for key in sparse.keys(): if key not in model.metabolites: raise Exception("cannot find the cytoplasmic metabolite %s in the model" % key) r = dict([(model.metabolites[model.metabolites.index(key)], val) for key, val in sparse.iteritems()]) reaction = Reaction(name) reaction.id = id reaction.add_metabolites(r) reaction.lower_bound = lower_bound reaction.upper_bound = upper_bound model.add_reactions([reaction]) return reaction
def convert_to_irreversible(model): """Split reversible reactions into two irreversible reactions These two reactions will proceed in opposite directions. This guarentees that all reactions in the model will only allow positive flux values, which is useful for some modeling problems. Arguments ---------- * model: cobra.Model ~ A Model object which will be modified in place. """ #warn("deprecated, not applicable for optlang solvers", DeprecationWarning) reactions_to_add = [] coefficients = {} for reaction in model.reactions: # If a reaction is reverse only, the forward reaction (which # will be constrained to 0) will be left in the model. if reaction.lower_bound < 0 and reaction.upper_bound > 0: reverse_reaction = Reaction(reaction.id + "_reverse") reverse_reaction.lower_bound = max(0, -reaction.upper_bound) reverse_reaction.upper_bound = -reaction.lower_bound coefficients[ reverse_reaction] = reaction.objective_coefficient * -1 reaction.lower_bound = max(0, reaction.lower_bound) reaction.upper_bound = max(0, reaction.upper_bound) # Make the directions aware of each other reaction.notes["reflection"] = reverse_reaction.id reverse_reaction.notes["reflection"] = reaction.id reaction_dict = { k: v * -1 for k, v in reaction._metabolites.items() } reverse_reaction.add_metabolites(reaction_dict) reverse_reaction._model = reaction._model reverse_reaction._genes = reaction._genes for gene in reaction._genes: gene._reaction.add(reverse_reaction) reverse_reaction.subsystem = reaction.subsystem reverse_reaction._gene_reaction_rule = reaction._gene_reaction_rule reactions_to_add.append(reverse_reaction) model.add_reactions(reactions_to_add) set_objective(model, coefficients, additive=True)
def test_make_lhs_irreversible_reversible(model): rxn = Reaction('test') rxn.add_metabolites({model.metabolites[0]: -1., model.metabolites[1]: 1.}) rxn.lower_bound = -1000. rxn.upper_bound = -100 model.add_reaction(rxn) assert rxn.lower_bound == -1000. assert rxn.upper_bound == -100. assert rxn.forward_variable.lb == 0. assert rxn.forward_variable.ub == 0. assert rxn.reverse_variable.lb == 100. assert rxn.reverse_variable.ub == 1000. rxn.upper_bound = 666. assert rxn.lower_bound == -1000. assert rxn.upper_bound == 666. assert rxn.forward_variable.lb == 0. assert rxn.forward_variable.ub == 666 assert rxn.reverse_variable.lb == 0. assert rxn.reverse_variable.ub == 1000.
def test_make_lhs_irreversible_reversible(model): rxn = Reaction('test') rxn.add_metabolites( {model.metabolites[0]: -1., model.metabolites[1]: 1.}) rxn.lower_bound = -1000. rxn.upper_bound = -100 model.add_reaction(rxn) assert rxn.lower_bound == -1000. assert rxn.upper_bound == -100. assert rxn.forward_variable.lb == 0. assert rxn.forward_variable.ub == 0. assert rxn.reverse_variable.lb == 100. assert rxn.reverse_variable.ub == 1000. rxn.upper_bound = 666. assert rxn.lower_bound == -1000. assert rxn.upper_bound == 666. assert rxn.forward_variable.lb == 0. assert rxn.forward_variable.ub == 666 assert rxn.reverse_variable.lb == 0. assert rxn.reverse_variable.ub == 1000.
def convert_to_irreversible(cobra_model): """Split reversible reactions into two irreversible reactions These two reactions will proceed in opposite directions. This guarentees that all reactions in the model will only allow positive flux values, which is useful for some modeling problems. cobra_model: A Model object which will be modified in place. """ warn("deprecated, not applicable for optlang solvers", DeprecationWarning) reactions_to_add = [] coefficients = {} for reaction in cobra_model.reactions: # If a reaction is reverse only, the forward reaction (which # will be constrained to 0) will be left in the model. if reaction.lower_bound < 0: reverse_reaction = Reaction(reaction.id + "_reverse") reverse_reaction.lower_bound = max(0, -reaction.upper_bound) reverse_reaction.upper_bound = -reaction.lower_bound coefficients[ reverse_reaction] = reaction.objective_coefficient * -1 reaction.lower_bound = max(0, reaction.lower_bound) reaction.upper_bound = max(0, reaction.upper_bound) # Make the directions aware of each other reaction.notes["reflection"] = reverse_reaction.id reverse_reaction.notes["reflection"] = reaction.id reaction_dict = {k: v * -1 for k, v in iteritems(reaction._metabolites)} reverse_reaction.add_metabolites(reaction_dict) reverse_reaction._model = reaction._model reverse_reaction._genes = reaction._genes for gene in reaction._genes: gene._reaction.add(reverse_reaction) reverse_reaction.subsystem = reaction.subsystem reverse_reaction._gene_reaction_rule = reaction._gene_reaction_rule reactions_to_add.append(reverse_reaction) cobra_model.add_reactions(reactions_to_add) set_objective(cobra_model, coefficients, additive=True)
def from_mat_struct(mat_struct, model_id=None, inf=inf): """create a model from the COBRA toolbox struct The struct will be a dict read in by scipy.io.loadmat """ m = mat_struct if m.dtype.names is None: raise ValueError("not a valid mat struct") if not {"rxns", "mets", "S", "lb", "ub"} <= set(m.dtype.names): raise ValueError("not a valid mat struct") if "c" in m.dtype.names: c_vec = m["c"][0, 0] else: c_vec = None warn("objective vector 'c' not found") model = Model() if model_id is not None: model.id = model_id elif "description" in m.dtype.names: description = m["description"][0, 0][0] if not isinstance(description, string_types) and len(description) > 1: model.id = description[0] warn("Several IDs detected, only using the first.") else: model.id = description else: model.id = "imported_model" for i, name in enumerate(m["mets"][0, 0]): new_metabolite = Metabolite() new_metabolite.id = str(name[0][0]) if all(var in m.dtype.names for var in ['metComps', 'comps', 'compNames']): comp_index = m["metComps"][0, 0][i][0] - 1 new_metabolite.compartment = m['comps'][0, 0][comp_index][0][0] if new_metabolite.compartment not in model.compartments: comp_name = m['compNames'][0, 0][comp_index][0][0] model.compartments[new_metabolite.compartment] = comp_name else: new_metabolite.compartment = _get_id_compartment(new_metabolite.id) if new_metabolite.compartment not in model.compartments: model.compartments[ new_metabolite.compartment] = new_metabolite.compartment try: new_metabolite.name = str(m["metNames"][0, 0][i][0][0]) except (IndexError, ValueError): pass try: new_metabolite.formula = str(m["metFormulas"][0][0][i][0][0]) except (IndexError, ValueError): pass try: new_metabolite.charge = float(m["metCharge"][0, 0][i][0]) int_charge = int(new_metabolite.charge) if new_metabolite.charge == int_charge: new_metabolite.charge = int_charge except (IndexError, ValueError): pass model.add_metabolites([new_metabolite]) new_reactions = [] coefficients = {} for i, name in enumerate(m["rxns"][0, 0]): new_reaction = Reaction() new_reaction.id = str(name[0][0]) new_reaction.lower_bound = float(m["lb"][0, 0][i][0]) new_reaction.upper_bound = float(m["ub"][0, 0][i][0]) if isinf(new_reaction.lower_bound) and new_reaction.lower_bound < 0: new_reaction.lower_bound = -inf if isinf(new_reaction.upper_bound) and new_reaction.upper_bound > 0: new_reaction.upper_bound = inf if c_vec is not None: coefficients[new_reaction] = float(c_vec[i][0]) try: new_reaction.gene_reaction_rule = str(m['grRules'][0, 0][i][0][0]) except (IndexError, ValueError): pass try: new_reaction.name = str(m["rxnNames"][0, 0][i][0][0]) except (IndexError, ValueError): pass try: new_reaction.subsystem = str(m['subSystems'][0, 0][i][0][0]) except (IndexError, ValueError): pass new_reactions.append(new_reaction) model.add_reactions(new_reactions) set_objective(model, coefficients) coo = scipy_sparse.coo_matrix(m["S"][0, 0]) for i, j, v in zip(coo.row, coo.col, coo.data): model.reactions[j].add_metabolites({model.metabolites[i]: v}) return model
def create_cobra_model_from_sbml_file(sbml_filename, old_sbml=False, legacy_metabolite=False, print_time=False, use_hyphens=False): """convert an SBML XML file into a cobra.Model object. Supports SBML Level 2 Versions 1 and 4. The function will detect if the SBML fbc package is used in the file and run the converter if the fbc package is used. Parameters ---------- sbml_filename: string old_sbml: bool Set to True if the XML file has metabolite formula appended to metabolite names. This was a poorly designed artifact that persists in some models. legacy_metabolite: bool If True then assume that the metabolite id has the compartment id appended after an underscore (e.g. _c for cytosol). This has not been implemented but will be soon. print_time: bool deprecated use_hyphens: bool If True, double underscores (__) in an SBML ID will be converted to hyphens Returns ------- Model : The parsed cobra model """ if not libsbml: raise ImportError('create_cobra_model_from_sbml_file ' 'requires python-libsbml') __default_lower_bound = -1000 __default_upper_bound = 1000 __default_objective_coefficient = 0 # Ensure that the file exists if not isfile(sbml_filename): raise IOError('Your SBML file is not found: %s' % sbml_filename) # Expressions to change SBML Ids to Palsson Lab Ids metabolite_re = re.compile('^M_') reaction_re = re.compile('^R_') compartment_re = re.compile('^C_') if print_time: warn("print_time is deprecated", DeprecationWarning) model_doc = libsbml.readSBML(sbml_filename) if model_doc.getPlugin("fbc") is not None: from libsbml import ConversionProperties, LIBSBML_OPERATION_SUCCESS conversion_properties = ConversionProperties() conversion_properties.addOption( "convert fbc to cobra", True, "Convert FBC model to Cobra model") result = model_doc.convert(conversion_properties) if result != LIBSBML_OPERATION_SUCCESS: raise Exception("Conversion of SBML+fbc to COBRA failed") sbml_model = model_doc.getModel() sbml_model_id = sbml_model.getId() sbml_species = sbml_model.getListOfSpecies() sbml_reactions = sbml_model.getListOfReactions() sbml_compartments = sbml_model.getListOfCompartments() compartment_dict = dict([(compartment_re.split(x.getId())[-1], x.getName()) for x in sbml_compartments]) if legacy_metabolite: # Deal with the palsson lab appending the compartment id to the # metabolite id new_dict = {} for the_id, the_name in compartment_dict.items(): if the_name == '': new_dict[the_id[0].lower()] = the_id else: new_dict[the_id] = the_name compartment_dict = new_dict legacy_compartment_converter = dict( [(v, k) for k, v in iteritems(compartment_dict)]) cobra_model = Model(sbml_model_id) metabolites = [] metabolite_dict = {} # Convert sbml_metabolites to cobra.Metabolites for sbml_metabolite in sbml_species: # Skip sbml boundary species if sbml_metabolite.getBoundaryCondition(): continue if (old_sbml or legacy_metabolite) and \ sbml_metabolite.getId().endswith('_b'): # Deal with incorrect sbml from bigg.ucsd.edu continue tmp_metabolite = Metabolite() metabolite_id = tmp_metabolite.id = sbml_metabolite.getId() tmp_metabolite.compartment = compartment_re.split( sbml_metabolite.getCompartment())[-1] if legacy_metabolite: if tmp_metabolite.compartment not in compartment_dict: tmp_metabolite.compartment = legacy_compartment_converter[ tmp_metabolite.compartment] tmp_metabolite.id = parse_legacy_id( tmp_metabolite.id, tmp_metabolite.compartment, use_hyphens=use_hyphens) if use_hyphens: tmp_metabolite.id = metabolite_re.split( tmp_metabolite.id)[-1].replace('__', '-') else: # Just in case the SBML ids are ill-formed and use - tmp_metabolite.id = metabolite_re.split( tmp_metabolite.id)[-1].replace('-', '__') tmp_metabolite.name = sbml_metabolite.getName() tmp_formula = '' tmp_metabolite.notes = parse_legacy_sbml_notes( sbml_metabolite.getNotesString()) if sbml_metabolite.isSetCharge(): tmp_metabolite.charge = sbml_metabolite.getCharge() if "CHARGE" in tmp_metabolite.notes: note_charge = tmp_metabolite.notes["CHARGE"][0] try: note_charge = float(note_charge) if note_charge == int(note_charge): note_charge = int(note_charge) except: warn("charge of %s is not a number (%s)" % (tmp_metabolite.id, str(note_charge))) else: if ((tmp_metabolite.charge is None) or (tmp_metabolite.charge == note_charge)): tmp_metabolite.notes.pop("CHARGE") # set charge to the one from notes if not assigend before # the same tmp_metabolite.charge = note_charge else: # tmp_metabolite.charge != note_charge msg = "different charges specified for %s (%d and %d)" msg = msg % (tmp_metabolite.id, tmp_metabolite.charge, note_charge) warn(msg) # Chances are a 0 note charge was written by mistake. We # will default to the note_charge in this case. if tmp_metabolite.charge == 0: tmp_metabolite.charge = note_charge for the_key in tmp_metabolite.notes.keys(): if the_key.lower() == 'formula': tmp_formula = tmp_metabolite.notes.pop(the_key)[0] break if tmp_formula == '' and old_sbml: tmp_formula = tmp_metabolite.name.split('_')[-1] tmp_metabolite.name = tmp_metabolite.name[:-len(tmp_formula) - 1] tmp_metabolite.formula = tmp_formula metabolite_dict.update({metabolite_id: tmp_metabolite}) metabolites.append(tmp_metabolite) cobra_model.add_metabolites(metabolites) # Construct the vectors and matrices for holding connectivity and numerical # info to feed to the cobra toolbox. # Always assume steady state simulations so b is set to 0 cobra_reaction_list = [] coefficients = {} for sbml_reaction in sbml_reactions: if use_hyphens: # Change the ids to match conventions used by the Palsson lab. reaction = Reaction(reaction_re.split( sbml_reaction.getId())[-1].replace('__', '-')) else: # Just in case the SBML ids are ill-formed and use - reaction = Reaction(reaction_re.split( sbml_reaction.getId())[-1].replace('-', '__')) cobra_reaction_list.append(reaction) # reaction.exchange_reaction = 0 reaction.name = sbml_reaction.getName() cobra_metabolites = {} # Use the cobra.Metabolite class here for sbml_metabolite in sbml_reaction.getListOfReactants(): tmp_metabolite_id = sbml_metabolite.getSpecies() # This deals with boundary metabolites if tmp_metabolite_id in metabolite_dict: tmp_metabolite = metabolite_dict[tmp_metabolite_id] cobra_metabolites[tmp_metabolite] = - \ sbml_metabolite.getStoichiometry() for sbml_metabolite in sbml_reaction.getListOfProducts(): tmp_metabolite_id = sbml_metabolite.getSpecies() # This deals with boundary metabolites if tmp_metabolite_id in metabolite_dict: tmp_metabolite = metabolite_dict[tmp_metabolite_id] # Handle the case where the metabolite was specified both # as a reactant and as a product. if tmp_metabolite in cobra_metabolites: warn("%s appears as a reactant and product %s" % (tmp_metabolite_id, reaction.id)) cobra_metabolites[ tmp_metabolite] += sbml_metabolite.getStoichiometry() # if the combined stoichiometry is 0, remove the metabolite if cobra_metabolites[tmp_metabolite] == 0: cobra_metabolites.pop(tmp_metabolite) else: cobra_metabolites[ tmp_metabolite] = sbml_metabolite.getStoichiometry() # check for nan for met, v in iteritems(cobra_metabolites): if isnan(v) or isinf(v): warn("invalid value %s for metabolite '%s' in reaction '%s'" % (str(v), met.id, reaction.id)) reaction.add_metabolites(cobra_metabolites) # Parse the kinetic law info here. parameter_dict = {} # If lower and upper bounds are specified in the Kinetic Law then # they override the sbml reversible attribute. If they are not # specified then the bounds are determined by getReversible. if not sbml_reaction.getKineticLaw(): if sbml_reaction.getReversible(): parameter_dict['lower_bound'] = __default_lower_bound parameter_dict['upper_bound'] = __default_upper_bound else: # Assume that irreversible reactions only proceed from left to # right. parameter_dict['lower_bound'] = 0 parameter_dict['upper_bound'] = __default_upper_bound parameter_dict[ 'objective_coefficient'] = __default_objective_coefficient else: for sbml_parameter in \ sbml_reaction.getKineticLaw().getListOfParameters(): parameter_dict[ sbml_parameter.getId().lower()] = sbml_parameter.getValue() if 'lower_bound' in parameter_dict: reaction.lower_bound = parameter_dict['lower_bound'] elif 'lower bound' in parameter_dict: reaction.lower_bound = parameter_dict['lower bound'] elif sbml_reaction.getReversible(): reaction.lower_bound = __default_lower_bound else: reaction.lower_bound = 0 if 'upper_bound' in parameter_dict: reaction.upper_bound = parameter_dict['upper_bound'] elif 'upper bound' in parameter_dict: reaction.upper_bound = parameter_dict['upper bound'] else: reaction.upper_bound = __default_upper_bound objective_coefficient = parameter_dict.get( 'objective_coefficient', parameter_dict.get( 'objective_coefficient', __default_objective_coefficient)) if objective_coefficient != 0: coefficients[reaction] = objective_coefficient # ensure values are not set to nan or inf if isnan(reaction.lower_bound) or isinf(reaction.lower_bound): reaction.lower_bound = __default_lower_bound if isnan(reaction.upper_bound) or isinf(reaction.upper_bound): reaction.upper_bound = __default_upper_bound reaction_note_dict = parse_legacy_sbml_notes( sbml_reaction.getNotesString()) # Parse the reaction notes. # POTENTIAL BUG: DEALING WITH LEGACY 'SBML' THAT IS NOT IN A # STANDARD FORMAT # TODO: READ IN OTHER NOTES AND GIVE THEM A reaction_ prefix. # TODO: Make sure genes get added as objects if 'GENE ASSOCIATION' in reaction_note_dict: rule = reaction_note_dict['GENE ASSOCIATION'][0] try: rule.encode('ascii') except (UnicodeEncodeError, UnicodeDecodeError): warn("gene_reaction_rule '%s' is not ascii compliant" % rule) if rule.startswith(""") and rule.endswith("""): rule = rule[6:-6] reaction.gene_reaction_rule = rule if 'GENE LIST' in reaction_note_dict: reaction.systematic_names = reaction_note_dict['GENE LIST'][0] elif ('GENES' in reaction_note_dict and reaction_note_dict['GENES'] != ['']): reaction.systematic_names = reaction_note_dict['GENES'][0] elif 'LOCUS' in reaction_note_dict: gene_id_to_object = dict([(x.id, x) for x in reaction._genes]) for the_row in reaction_note_dict['LOCUS']: tmp_row_dict = {} the_row = 'LOCUS:' + the_row.lstrip('_').rstrip('#') for the_item in the_row.split('#'): k, v = the_item.split(':') tmp_row_dict[k] = v tmp_locus_id = tmp_row_dict['LOCUS'] if 'TRANSCRIPT' in tmp_row_dict: tmp_locus_id = tmp_locus_id + \ '.' + tmp_row_dict['TRANSCRIPT'] if 'ABBREVIATION' in tmp_row_dict: gene_id_to_object[tmp_locus_id].name = tmp_row_dict[ 'ABBREVIATION'] if 'SUBSYSTEM' in reaction_note_dict: reaction.subsystem = reaction_note_dict.pop('SUBSYSTEM')[0] reaction.notes = reaction_note_dict # Now, add all of the reactions to the model. cobra_model.id = sbml_model.getId() # Populate the compartment list - This will be done based on # cobra.Metabolites in cobra.Reactions in the future. cobra_model.compartments = compartment_dict cobra_model.add_reactions(cobra_reaction_list) set_objective(cobra_model, coefficients) return cobra_model
def parse_xml_into_model(xml, number=float): xml_model = xml.find(ns("sbml:model")) if get_attrib(xml_model, "fbc:strict") != "true": warn('loading SBML model without fbc:strict="true"') model_id = get_attrib(xml_model, "id") model = Model(model_id) model.name = xml_model.get("name") model.compartments = {c.get("id"): c.get("name") for c in xml_model.findall(COMPARTMENT_XPATH)} # add metabolites for species in xml_model.findall(SPECIES_XPATH % 'false'): met = get_attrib(species, "id", require=True) met = Metabolite(clip(met, "M_")) met.name = species.get("name") annotate_cobra_from_sbml(met, species) met.compartment = species.get("compartment") met.charge = get_attrib(species, "fbc:charge", int) met.formula = get_attrib(species, "fbc:chemicalFormula") model.add_metabolites([met]) # Detect boundary metabolites - In case they have been mistakenly # added. They should not actually appear in a model boundary_metabolites = {clip(i.get("id"), "M_") for i in xml_model.findall(SPECIES_XPATH % 'true')} # add genes for sbml_gene in xml_model.iterfind(GENES_XPATH): gene_id = get_attrib(sbml_gene, "fbc:id").replace(SBML_DOT, ".") gene = Gene(clip(gene_id, "G_")) gene.name = get_attrib(sbml_gene, "fbc:name") if gene.name is None: gene.name = get_attrib(sbml_gene, "fbc:label") annotate_cobra_from_sbml(gene, sbml_gene) model.genes.append(gene) def process_gpr(sub_xml): """recursively convert gpr xml to a gpr string""" if sub_xml.tag == OR_TAG: return "( " + ' or '.join(process_gpr(i) for i in sub_xml) + " )" elif sub_xml.tag == AND_TAG: return "( " + ' and '.join(process_gpr(i) for i in sub_xml) + " )" elif sub_xml.tag == GENEREF_TAG: gene_id = get_attrib(sub_xml, "fbc:geneProduct", require=True) return clip(gene_id, "G_") else: raise Exception("unsupported tag " + sub_xml.tag) bounds = {bound.get("id"): get_attrib(bound, "value", type=number) for bound in xml_model.iterfind(BOUND_XPATH)} # add reactions reactions = [] for sbml_reaction in xml_model.iterfind( ns("sbml:listOfReactions/sbml:reaction")): reaction = get_attrib(sbml_reaction, "id", require=True) reaction = Reaction(clip(reaction, "R_")) reaction.name = sbml_reaction.get("name") annotate_cobra_from_sbml(reaction, sbml_reaction) lb_id = get_attrib(sbml_reaction, "fbc:lowerFluxBound", require=True) ub_id = get_attrib(sbml_reaction, "fbc:upperFluxBound", require=True) try: reaction.upper_bound = bounds[ub_id] reaction.lower_bound = bounds[lb_id] except KeyError as e: raise CobraSBMLError("No constant bound with id '%s'" % str(e)) reactions.append(reaction) stoichiometry = defaultdict(lambda: 0) for species_reference in sbml_reaction.findall( ns("sbml:listOfReactants/sbml:speciesReference")): met_name = clip(species_reference.get("species"), "M_") stoichiometry[met_name] -= \ number(species_reference.get("stoichiometry")) for species_reference in sbml_reaction.findall( ns("sbml:listOfProducts/sbml:speciesReference")): met_name = clip(species_reference.get("species"), "M_") stoichiometry[met_name] += \ get_attrib(species_reference, "stoichiometry", type=number, require=True) # needs to have keys of metabolite objects, not ids object_stoichiometry = {} for met_id in stoichiometry: if met_id in boundary_metabolites: warn("Boundary metabolite '%s' used in reaction '%s'" % (met_id, reaction.id)) continue try: metabolite = model.metabolites.get_by_id(met_id) except KeyError: warn("ignoring unknown metabolite '%s' in reaction %s" % (met_id, reaction.id)) continue object_stoichiometry[metabolite] = stoichiometry[met_id] reaction.add_metabolites(object_stoichiometry) # set gene reaction rule gpr_xml = sbml_reaction.find(GPR_TAG) if gpr_xml is not None and len(gpr_xml) != 1: warn("ignoring invalid geneAssociation for " + repr(reaction)) gpr_xml = None gpr = process_gpr(gpr_xml[0]) if gpr_xml is not None else '' # remove outside parenthesis, if any if gpr.startswith("(") and gpr.endswith(")"): gpr = gpr[1:-1].strip() gpr = gpr.replace(SBML_DOT, ".") reaction.gene_reaction_rule = gpr try: model.add_reactions(reactions) except ValueError as e: warn(str(e)) # objective coefficients are handled after all reactions are added obj_list = xml_model.find(ns("fbc:listOfObjectives")) if obj_list is None: warn("listOfObjectives element not found") return model target_objective_id = get_attrib(obj_list, "fbc:activeObjective") target_objective = obj_list.find( ns("fbc:objective[@fbc:id='{}']".format(target_objective_id))) obj_direction_long = get_attrib(target_objective, "fbc:type") obj_direction = LONG_SHORT_DIRECTION[obj_direction_long] obj_query = OBJECTIVES_XPATH % target_objective_id coefficients = {} for sbml_objective in obj_list.findall(obj_query): rxn_id = clip(get_attrib(sbml_objective, "fbc:reaction"), "R_") try: objective_reaction = model.reactions.get_by_id(rxn_id) except KeyError: raise CobraSBMLError("Objective reaction '%s' not found" % rxn_id) try: coefficients[objective_reaction] = get_attrib( sbml_objective, "fbc:coefficient", type=number) except ValueError as e: warn(str(e)) set_objective(model, coefficients) model.solver.objective.direction = obj_direction return model
#add reactions to represent day-night metabolite accumulation from cobra.core import Metabolite, Reaction #Adding transfer reactions tmfile = open("MetabolitesToTransfer.txt", "r") tmset = set() for line in tmfile: tmset.add(line.replace("\n", "")) for met in tmset: tempRxn = Reaction(met + "_dielTransfer") tempRxn.add_metabolites({ cobra_model.metabolites.get_by_id(met + "1"): -1, cobra_model.metabolites.get_by_id(met + "2"): 1 }) tempRxn.lower_bound = -1000 if not ((met == "STARCH_p") or (met == "SUCROSE_v") or (met == "MAL_v") or (met == "aMAL_v") or (met == "NITRATE_v") or (met == "CIT_v") or (met == "aCIT_v") or (met == "PROTON_v")): tempRxn.lower_bound = 0 tempRxn.upper_bound = 1000 cobra_model.add_reaction(tempRxn) fractionMets = dict() for rxn in cobra_model.reactions: for met in rxn.metabolites.keys(): a = re.search("^a{1,3}", met.id) anion = "" if a: anion = a.group(0) b = re.search("^b{1,3}", met.id)
def optimize_minimum_flux(model, objective_sense='maximize', tolerance_optimality=1e-8, tolerance_feasibility=1e-8): # return the flux distribution in which the total amount of fluxes is minimum while the growth is maximum #Get the optimal wt objective value and adjust based on optimality tolerances model.optimize() optimal_value = deepcopy(model.solution.f) # print('opt val: %s' % optimal_value) if objective_sense == 'maximize': optimal_value = floor(optimal_value/tolerance_optimality)*tolerance_optimality else: optimal_value = ceil(optimal_value/tolerance_optimality)*tolerance_optimality # print('adjusted opt val: %s' % optimal_value) #Add in the virtual objective metabolite to constrain the wt_model to the space where #the objective was maximal objective_metabolite = Metabolite('objective metabolite') objective_metabolite._bound = optimal_value if objective_sense == 'maximize': objective_metabolite._constraint_sense = 'G' else: objective_metabolite._constraint_sense = 'L' # print('objm const sense: %s, objm bound: %s' % (objective_metabolite._constraint_sense, objective_metabolite._bound)) # construct irreversible model to assure all flux values are positive irreve_model = model.copy() # this is necessary to avoid invalid bound error when model is changed to irreversible for r in irreve_model.reactions: if r.upper_bound < 0: reverse_reaction = Reaction(r.id + "_reverse") reverse_reaction.lower_bound = r.upper_bound * -1 reverse_reaction.upper_bound = r.lower_bound * -1 reverse_reaction.objective_coefficient = r.objective_coefficient * -1 reaction_dict = dict([(k, v*-1) for k, v in r.metabolites.items()]) reverse_reaction.add_metabolites(reaction_dict) irreve_model.add_reaction(reverse_reaction) r.upper_bound, r.lower_bound = 0, 0 cobra.manipulation.modify.convert_to_irreversible(irreve_model) objective_reaction_coefficient_dict = dict([(x.id, x.objective_coefficient) for x in model.reactions if x.objective_coefficient]) # this couples the objective reaction to the virtual metabolite [irreve_model.reactions.get_by_id(k).add_metabolites({objective_metabolite: v}) for k, v in objective_reaction_coefficient_dict.items()] # print('irregular metabolites: %s' % [(m.id, m._constraint_sense, m._bound) # for m in irreve_model.metabolites if m._constraint_sense != 'E' or m._bound != 0]) # minimize the sum of fluxes for r in irreve_model.reactions: r.objective_coefficient = 1 # print([r.id for r in irreve_model.reactions if r.objective_coefficient != 1]) # print(tolerance_feasibility) irreve_model.optimize(objective_sense='minimize', tolerance_feasibility=tolerance_feasibility) # adjust this to the solution of wt_model original_flux = model.solution.x_dict irreve_flux = irreve_model.solution.x_dict for k in original_flux.keys(): original_flux[k] = irreve_flux[k] # if reverse reaction exists and its flux is not zero, assign as a negative flux in wt_flux if k + '_reverse' in irreve_flux.keys() and irreve_flux[k + '_reverse'] != 0: if irreve_flux[k] != 0: print('Attention: non-optimal solution') original_flux[k] = -irreve_flux[k + '_reverse'] model.solution.status = irreve_model.solution.status model.solution.f = sum([irreve_model.reactions.get_by_id(k).x * v for k, v in objective_reaction_coefficient_dict.items()]) return model.solution