def test_gapfilling(salmonella): """Test Gapfilling.""" m = Model() m.add_metabolites([Metabolite(m_id) for m_id in ["a", "b", "c"]]) exa = Reaction("EX_a") exa.add_metabolites({m.metabolites.a: 1}) b2c = Reaction("b2c") b2c.add_metabolites({m.metabolites.b: -1, m.metabolites.c: 1}) dmc = Reaction("DM_c") dmc.add_metabolites({m.metabolites.c: -1}) m.add_reactions([exa, b2c, dmc]) m.objective = 'DM_c' universal = Model() a2b = Reaction("a2b") a2d = Reaction("a2d") universal.add_reactions([a2b, a2d]) a2b.build_reaction_from_string("a --> b", verbose=False) a2d.build_reaction_from_string("a --> d", verbose=False) # # GrowMatch # result = gapfilling.growMatch(m, universal)[0] result = gapfill(m, universal)[0] assert len(result) == 1 assert result[0].id == "a2b" # # SMILEY # result = gapfilling.SMILEY(m, "b", universal)[0] with m: m.objective = m.add_boundary(m.metabolites.b, type='demand') result = gapfill(m, universal)[0] assert len(result) == 1 assert result[0].id == "a2b" # # 2 rounds of GrowMatch with exchange reactions # result = gapfilling.growMatch(m, None, ex_rxns=True, iterations=2) result = gapfill(m, None, exchange_reactions=True, iterations=2) assert len(result) == 2 assert len(result[0]) == 1 assert len(result[1]) == 1 assert {i[0].id for i in result} == {"EX_b", "EX_c"} # somewhat bigger model universal = Model("universal_reactions") with salmonella as model: for i in [i.id for i in model.metabolites.f6p_c.reactions]: reaction = model.reactions.get_by_id(i) universal.add_reactions([reaction.copy()]) model.remove_reactions([reaction]) gf = GapFiller(model, universal, penalties={'TKT2': 1e3}, demand_reactions=False) solution = gf.fill() assert 'TKT2' not in {r.id for r in solution[0]} assert gf.validate(solution[0])
def _integer_iterative_binary_gapfill(model, phenotype_dict, cycle_order, universal=None, output_ensemble_size=0, lower_bound=0.05, penalties=False, demand_reactions=False, exchange_reactions=False, integer_threshold=1E-6): gapfiller = GapFiller(model, universal=universal, lower_bound=lower_bound, penalties=penalties, demand_reactions=demand_reactions, exchange_reactions=exchange_reactions, integer_threshold=integer_threshold) original_costs = gapfiller.costs solutions = [] for cycle_num in range(0, output_ensemble_size): print("starting cycle number " + str(cycle_num)) cycle_reactions = set() for condition in cycle_order[cycle_num]: gapfiller.model.medium = phenotype_dict[condition] # gapfill and get the solution. The 0 index is necessary because # gapfill will return a list of lists; we are only taking the # first (and only) list here. gapfilled_reactions = gapfiller.fill()[0] cycle_reactions = cycle_reactions | set(gapfilled_reactions) # iterate through indicators, find those corresponding to the # gapfilled reactions from any iteration within this cycle, and # reset their cost to 0. Doing this for all reactions from any # iteration within the cycle is necessary because cobrapy's # gapfill function performs update_costs, which will reset costs # and iteratively increase them; without this manual override # performed here, costs for previous conditions within a cycle # would revert to 1 instead of the desired 0 for reaction_indicator in [ indicator for indicator in gapfiller.indicators ]: if reaction_indicator.rxn_id in cycle_reactions: gapfiller.costs[reaction_indicator] = 0 gapfiller.model.objective.set_linear_coefficients(gapfiller.costs) solutions.append(list(cycle_reactions)) gapfiller.model.objective.set_linear_coefficients(original_costs) return solutions
def test_optimization(self): model = cobra.io.read_sbml_model("../models/enhanced_model_ecoli.xml") gapfiller = GapFiller(model, Model(), demand_reactions=True, exchange_reactions=True, integer_threshold=1e-300) solution = gapfiller.fill(iterations=1) print(solution) model.add_reactions(solution[0]) print(model.optimize().objective_value) cobra.io.write_sbml_model(model, "enhanced_model_ecoli2.xml") cobra.io.save_json_model(model, "enhanced_model_ecoli.json")
def test_gapfilling(salmonella): """Test Gapfilling.""" m = Model() m.add_metabolites([Metabolite(m_id) for m_id in ["a", "b", "c"]]) exa = Reaction("EX_a") exa.add_metabolites({m.metabolites.a: 1}) b2c = Reaction("b2c") b2c.add_metabolites({m.metabolites.b: -1, m.metabolites.c: 1}) dmc = Reaction("DM_c") dmc.add_metabolites({m.metabolites.c: -1}) m.add_reactions([exa, b2c, dmc]) m.objective = 'DM_c' universal = Model() a2b = Reaction("a2b") a2d = Reaction("a2d") universal.add_reactions([a2b, a2d]) a2b.build_reaction_from_string("a --> b", verbose=False) a2d.build_reaction_from_string("a --> d", verbose=False) # # GrowMatch # result = gapfilling.growMatch(m, universal)[0] result = gapfill(m, universal)[0] assert len(result) == 1 assert result[0].id == "a2b" # # SMILEY # result = gapfilling.SMILEY(m, "b", universal)[0] with m: m.objective = m.add_boundary(m.metabolites.b, type='demand') result = gapfill(m, universal)[0] assert len(result) == 1 assert result[0].id == "a2b" # # 2 rounds of GrowMatch with exchange reactions # result = gapfilling.growMatch(m, None, ex_rxns=True, iterations=2) result = gapfill(m, None, exchange_reactions=True, iterations=2) assert len(result) == 2 assert len(result[0]) == 1 assert len(result[1]) == 1 assert {i[0].id for i in result} == {"EX_b", "EX_c"} # # Gapfilling solution adds metabolites not present in original model # test for when demand = T # a demand reaction must be added to clear new metabolite universal_noDM = Model() a2b = Reaction("a2b") universal_noDM.add_reactions([a2b]) a2b.build_reaction_from_string("a --> b + d", verbose=False) result = gapfill(m, universal_noDM, exchange_reactions=False, demand_reactions=True)[0] # add reaction a2b and demand reaction to clear met d assert len(result) == 2 assert "a2b" in [x.id for x in result] # test for when demand = False # test for when metabolites are added to the model and # must be cleared by other reactions in universal model # (i.e. not necessarily a demand reaction) universal_withDM = universal_noDM.copy() d_dm = Reaction("d_dm") universal_withDM.add_reactions([d_dm]) d_dm.build_reaction_from_string("d -->", verbose=False) result = gapfill(m, universal_withDM, exchange_reactions=False, demand_reactions=False)[0] assert len(result) == 2 assert "a2b" in [x.id for x in result] # somewhat bigger model universal = Model("universal_reactions") with salmonella as model: for i in [i.id for i in model.metabolites.f6p_c.reactions]: reaction = model.reactions.get_by_id(i) universal.add_reactions([reaction.copy()]) model.remove_reactions([reaction]) gf = GapFiller(model, universal, penalties={'TKT2': 1e3}, demand_reactions=False) solution = gf.fill() assert 'TKT2' not in {r.id for r in solution[0]} assert gf.validate(solution[0])
def gapfill_to_ensemble(model, iterations=1, universal=None, lower_bound=0.05, penalties=None, exchange_reactions=False, demand_reactions=False, integer_threshold=1e-6): """ Performs gapfilling on model, pulling reactions from universal. Any existing constraints on base_model are maintained during gapfilling, so these should be set before calling gapfill_to_ensemble (e.g. secretion of metabolites, choice of objective function etc.). Currently, only iterative solutions are supported with accumulating penalties (i.e. after each iteration, the penalty for each reaction doubles). Parameters ---------- model : cobra.Model The model to perform gap filling on. universal : cobra.Model A universal model with reactions that can be used to complete the model. lower_bound : float, 0.05 The minimally accepted flux for the objective in the filled model. penalties : dict, None A dictionary with keys being 'universal' (all reactions included in the universal model), 'exchange' and 'demand' (all additionally added exchange and demand reactions) for the three reaction types. Can also have reaction identifiers for reaction specific costs. Defaults are 1, 100 and 1 respectively. integer_threshold : float, 1e-6 The threshold at which a value is considered non-zero (aka integrality threshold). If gapfilled models fail to validate, you may want to lower this value. However, picking a threshold that is too low may also result in reactions being added that are not essential to meet the imposed constraints. exchange_reactions : bool, False Consider adding exchange (uptake) reactions for all metabolites in the model. demand_reactions : bool, False Consider adding demand reactions for all metabolites. Returns ------- ensemble : medusa.core.Ensemble The ensemble object created from the gapfill solutions. """ gapfiller = GapFiller(model, universal=universal, lower_bound=lower_bound, penalties=penalties, demand_reactions=demand_reactions, exchange_reactions=exchange_reactions, integer_threshold=integer_threshold) solutions = gapfiller.fill(iterations=iterations) print("finished gap-filling. Constructing ensemble...") ensemble = _build_ensemble_from_gapfill_solutions(model, solutions, universal=universal) return ensemble
def test_gapfilling(salmonella: Model) -> None: """Test Gapfilling.""" m = Model() m.add_metabolites([Metabolite(m_id) for m_id in ["a", "b", "c"]]) exa = Reaction("EX_a") exa.add_metabolites({m.metabolites.a: 1}) b2c = Reaction("b2c") b2c.add_metabolites({m.metabolites.b: -1, m.metabolites.c: 1}) dmc = Reaction("DM_c") dmc.add_metabolites({m.metabolites.c: -1}) m.add_reactions([exa, b2c, dmc]) m.objective = "DM_c" universal = Model() a2b = Reaction("a2b") a2d = Reaction("a2d") universal.add_reactions([a2b, a2d]) a2b.build_reaction_from_string("a --> b", verbose=False) a2d.build_reaction_from_string("a --> d", verbose=False) # # GrowMatch # result = gapfilling.growMatch(m, universal)[0] result = gapfill(m, universal)[0] assert len(result) == 1 assert result[0].id == "a2b" # # SMILEY # result = gapfilling.SMILEY(m, "b", universal)[0] with m: m.objective = m.add_boundary(m.metabolites.b, type="demand") result = gapfill(m, universal)[0] assert len(result) == 1 assert result[0].id == "a2b" # # 2 rounds of GrowMatch with exchange reactions # result = gapfilling.growMatch(m, None, ex_rxns=True, iterations=2) result = gapfill(m, None, exchange_reactions=True, iterations=2) assert len(result) == 2 assert len(result[0]) == 1 assert len(result[1]) == 1 assert {i[0].id for i in result} == {"EX_b", "EX_c"} # # Gapfilling solution adds metabolites not present in original model # test for when demand = T # a demand reaction must be added to clear new metabolite universal_noDM = Model() a2b = Reaction("a2b") universal_noDM.add_reactions([a2b]) a2b.build_reaction_from_string("a --> b + d", verbose=False) result = gapfill(m, universal_noDM, exchange_reactions=False, demand_reactions=True)[0] # add reaction a2b and demand reaction to clear met d assert len(result) == 2 assert "a2b" in [x.id for x in result] # test for when demand = False # test for when metabolites are added to the model and # must be cleared by other reactions in universal model # (i.e. not necessarily a demand reaction) universal_withDM = universal_noDM.copy() d_dm = Reaction("d_dm") universal_withDM.add_reactions([d_dm]) d_dm.build_reaction_from_string("d -->", verbose=False) result = gapfill(m, universal_withDM, exchange_reactions=False, demand_reactions=False)[0] assert len(result) == 2 assert "a2b" in [x.id for x in result] # somewhat bigger model universal = Model("universal_reactions") with salmonella as model: for i in [i.id for i in model.metabolites.f6p_c.reactions]: reaction = model.reactions.get_by_id(i) universal.add_reactions([reaction.copy()]) model.remove_reactions([reaction]) gf = GapFiller(model, universal, penalties={"TKT2": 1e3}, demand_reactions=False) solution = gf.fill() assert "TKT2" not in {r.id for r in solution[0]} assert gf.validate(solution[0])