def __init__(self, reactions=None, essential_reactions=None, use_nullspace_simplification=True, *args, **kwargs): super(ReactionKnockoutOptimization, self).__init__(*args, **kwargs) if reactions is None: self.reactions = set([r.id for r in self.model.reactions]) else: self.reactions = reactions logger.debug("Computing essential reactions...") if essential_reactions is None: self.essential_reactions = set( r.id for r in find_essential_reactions(self.model, processes=1)) else: self.essential_reactions = set([ r.id for r in find_essential_reactions(self.model, processes=1) ]) self.essential_reactions.update(essential_reactions) if use_nullspace_simplification: ns = nullspace(create_stoichiometric_array(self.model)) dead_ends = set(find_blocked_reactions_nullspace(self.model, ns=ns)) exchanges = set(self.model.boundary) reactions = [ r for r in self.model.reactions if (r not in exchanges) and (r not in dead_ends) and ( r.id not in self.essential_reactions) ] groups = find_coupled_reactions_nullspace(self.model, ns=ns) groups_keys = [ set(group) for group in groups if any(r.id in reactions for r in group) ] reduced_set = reduce_reaction_set(reactions, groups_keys) to_keep = [r.id for r in reduced_set] else: groups = None to_keep = set(r.id for r in self.model.reactions) to_keep.difference_update(r.id for r in self.model.boundary) to_keep.difference_update(self.essential_reactions) to_keep = list(to_keep) self.representation = to_keep self._target_type = REACTION_KNOCKOUT_TYPE self._decoder = decoders.ReactionSetDecoder(self.representation, self.model, groups=groups) self._evaluator = evaluators.KnockoutEvaluator( model=self.model, decoder=self._decoder, objective_function=self.objective_function, simulation_method=self._simulation_method, simulation_kwargs=self._simulation_kwargs)
def test_coupled_reactions(self, core_model): # If a reaction is essential, all coupled reactions are essential essential_reactions = find_essential_reactions(core_model) coupled_reactions = structural.find_coupled_reactions_nullspace(core_model) for essential_reaction in essential_reactions: for group in coupled_reactions: assert isinstance(group, dict) if essential_reaction in group: assert all(group_reaction in essential_reactions for group_reaction in group)
def test_coupled_reactions(self, core_model): # If a reaction is essential, all coupled reactions are essential essential_reactions = find_essential_reactions(core_model) coupled_reactions = structural.find_coupled_reactions_nullspace(core_model) for essential_reaction in essential_reactions: for group in coupled_reactions: assert isinstance(group, dict) if essential_reaction in group: assert all(group_reaction in essential_reactions for group_reaction in group)
def __init__(self, reactions=None, essential_reactions=None, use_nullspace_simplification=True, *args, **kwargs): super(ReactionKnockoutOptimization, self).__init__(*args, **kwargs) if reactions is None: self.reactions = set([r.id for r in self.model.reactions]) else: self.reactions = reactions logger.debug("Computing essential reactions...") if essential_reactions is None: self.essential_reactions = set(r.id for r in find_essential_reactions(self.model, processes=1)) else: self.essential_reactions = set([r.id for r in find_essential_reactions(self.model, processes=1)]) self.essential_reactions.update(essential_reactions) if use_nullspace_simplification: ns = nullspace(create_stoichiometric_array(self.model)) dead_ends = set(find_blocked_reactions_nullspace(self.model, ns=ns)) exchanges = set(self.model.boundary) reactions = [ r for r in self.model.reactions if (r not in exchanges) and ( r not in dead_ends) and ( r.id not in self.essential_reactions) ] groups = find_coupled_reactions_nullspace(self.model, ns=ns) groups_keys = [set(group) for group in groups if any(r.id in reactions for r in group)] reduced_set = reduce_reaction_set(reactions, groups_keys) to_keep = [r.id for r in reduced_set] else: groups = None to_keep = set(r.id for r in self.model.reactions) to_keep.difference_update(r.id for r in self.model.boundary) to_keep.difference_update(self.essential_reactions) to_keep = list(to_keep) self.representation = to_keep self._target_type = REACTION_KNOCKOUT_TYPE self._decoder = decoders.ReactionSetDecoder(self.representation, self.model, groups=groups) self._evaluator = evaluators.KnockoutEvaluator(model=self.model, decoder=self._decoder, objective_function=self.objective_function, simulation_method=self._simulation_method, simulation_kwargs=self._simulation_kwargs)
def _build_problem(self, essential_reactions, use_nullspace_simplification): logger.debug("Starting to formulate OptKnock problem") self.essential_reactions = find_essential_reactions(self._model).union( self._model.exchanges) if essential_reactions: self.essential_reactions.update( set( get_reaction_for(self._model, r) for r in essential_reactions)) reactions = set(self._model.reactions) - self.essential_reactions if use_nullspace_simplification: reactions = self._reduce_to_nullspace(reactions) else: self.reaction_groups = None self._make_dual() self._combine_primal_and_dual() logger.debug("Primal and dual successfully combined") y_vars = {} constrained_dual_vars = set() for reaction in reactions: if reaction not in self.essential_reactions and reaction.lower_bound <= 0 <= reaction.upper_bound: y_var, constrained_vars = self._add_knockout_constraints( reaction) y_vars[y_var] = reaction constrained_dual_vars.update(constrained_vars) self._y_vars = y_vars primal_objective = self._model.solver.objective dual_objective = self._model.solver.interface.Objective.clone( self._dual_problem.objective, model=self._model.solver) reduced_expression = Add(*((c * v) for v, c in dual_objective. expression.as_coefficients_dict().items() if v not in constrained_dual_vars)) dual_objective = self._model.solver.interface.Objective( reduced_expression, direction=dual_objective.direction) optimality_constraint = self._model.solver.interface.Constraint( primal_objective.expression - dual_objective.expression, lb=0, ub=0, name="inner_optimality") self._model.solver.add(optimality_constraint) logger.debug("Inner optimality constrained") logger.debug("Adding constraint for number of knockouts") knockout_number_constraint = self._model.solver.interface.Constraint( Add(*y_vars), lb=len(y_vars), ub=len(y_vars)) self._model.solver.add(knockout_number_constraint) self._number_of_knockouts_constraint = knockout_number_constraint
def __init__(self, reactions=None, essential_reactions=None, *args, **kwargs): super(MultiprocessReactionKnockoutOptimization, self).__init__(*args, **kwargs) if reactions is None: self.reactions = set([r.id for r in self.model.reactions]) else: self.reactions = reactions if essential_reactions is None: self.essential_reactions = set([r.id for r in find_essential_reactions(self.model, processes=1)]) else: self.essential_reactions = essential_reactions
def __init__(self, reactions=None, essential_reactions=None, *args, **kwargs): super(MultiprocessReactionKnockoutOptimization, self).__init__(*args, **kwargs) if reactions is None: self.reactions = set([r.id for r in self.model.reactions]) else: self.reactions = reactions if essential_reactions is None: self.essential_reactions = set([r.id for r in find_essential_reactions(self.model, processes=1)]) else: self.essential_reactions = essential_reactions
def test_lmoma_with_cache(self, core_model): original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() lmoma(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("u_") for v in core_model.solver.variables) assert any(c.name.startswith("lmoma_const_") for c in core_model.solver.constraints) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("u_") for v in core_model.solver.variables) assert not any(c.name.startswith("lmoma_const_") for c in core_model.solver.constraints)
def find_essential_nutrients(species_list, cpu_count): from cobra.flux_analysis import find_essential_reactions essentials = {} counter = 0 for species in species_list: for exchange in species.model.exchanges: exchange.lower_bound = -1000.0 exchange.upper_bound = 1000.0 ess = find_essential_reactions(species.model, 0.001, cpu_count) for reaction in ess: if reaction.id[:3] == "EX_": if reaction.id not in essentials: essentials[reaction.id] = counter counter += 1 #print(reaction.id) return counter, essentials
def test_lmoma_with_cache(self, core_model): original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() lmoma(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("u_") for v in core_model.solver.variables) assert any(c.name.startswith("lmoma_const_") for c in core_model.solver.constraints) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("u_") for v in core_model.solver.variables) assert not any(c.name.startswith("lmoma_const_") for c in core_model.solver.constraints)
def test_moma_with_cache(self, core_model): if current_solver_name(core_model) == 'glpk': pytest.skip('glpk does not support qp') original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() moma(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("moma_aux_") for v in core_model.solver.variables) assert any(c.name.startswith("moma_const_") for c in core_model.solver.constraints) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("moma_aux_") for v in core_model.solver.variables) assert not any(c.name.startswith("moma_const_") for c in core_model.solver.constraints)
def test_moma_with_cache(self, core_model): if current_solver_name(core_model) == 'glpk': pytest.skip('glpk does not support qp') original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() moma(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("moma_aux_") for v in core_model.solver.variables) assert any(c.name.startswith("moma_const_") for c in core_model.solver.constraints) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("moma_aux_") for v in core_model.solver.variables) assert not any(c.name.startswith("moma_const_") for c in core_model.solver.constraints)
def test_reactions_in_group_become_blocked_if_one_is_removed(self, core_model): essential_reactions = find_essential_reactions(core_model) coupled_reactions = structural.find_coupled_reactions_nullspace(core_model) for group in coupled_reactions: representative = pick_one(group) if representative not in essential_reactions: with core_model: assert core_model == representative.model core_model.remove_reactions([representative]) # # FIXME: Hack because of optlang queue issues with GLPK # core_model.solver.update() assert representative not in core_model.reactions assert representative.forward_variable not in core_model.solver.variables assert representative.reverse_variable not in core_model.solver.variables assert representative not in core_model.reactions assert representative.model is None blocked_reactions = find_blocked_reactions(core_model) assert all(r in blocked_reactions for r in group if r != representative) assert representative in core_model.reactions coupled_reactions = structural.find_coupled_reactions(core_model) for group in coupled_reactions: representative = pick_one(group) if representative not in essential_reactions: with core_model: fwd_var_name = representative.forward_variable.name rev_var_name = representative.reverse_variable.name assert core_model == representative.model core_model.remove_reactions([representative]) # # FIXME: Hack because of optlang queue issues with GLPK # core_model.solver.update() assert representative not in core_model.reactions assert fwd_var_name not in core_model.solver.variables assert rev_var_name not in core_model.solver.variables assert representative not in core_model.reactions assert representative.model is None blocked_reactions = find_blocked_reactions(core_model) assert representative not in core_model.reactions assert all(r in blocked_reactions for r in group if r != representative) assert representative in core_model.reactions
def test_reactions_in_group_become_blocked_if_one_is_removed(self, core_model): essential_reactions = find_essential_reactions(core_model) coupled_reactions = structural.find_coupled_reactions_nullspace(core_model) for group in coupled_reactions: representative = pick_one(group) if representative not in essential_reactions: with core_model: assert core_model == representative.model core_model.remove_reactions([representative]) # # FIXME: Hack because of optlang queue issues with GLPK # core_model.solver.update() assert representative not in core_model.reactions assert representative.forward_variable not in core_model.solver.variables assert representative.reverse_variable not in core_model.solver.variables assert representative not in core_model.reactions assert representative.model is None blocked_reactions = find_blocked_reactions(core_model) assert all(r in blocked_reactions for r in group if r != representative) assert representative in core_model.reactions coupled_reactions = structural.find_coupled_reactions(core_model) for group in coupled_reactions: representative = pick_one(group) if representative not in essential_reactions: with core_model: fwd_var_name = representative.forward_variable.name rev_var_name = representative.reverse_variable.name assert core_model == representative.model core_model.remove_reactions([representative]) # # FIXME: Hack because of optlang queue issues with GLPK # core_model.solver.update() assert representative not in core_model.reactions assert fwd_var_name not in core_model.solver.variables assert rev_var_name not in core_model.solver.variables assert representative not in core_model.reactions assert representative.model is None blocked_reactions = find_blocked_reactions(core_model) assert representative not in core_model.reactions assert all(r in blocked_reactions for r in group if r != representative) assert representative in core_model.reactions
def test_room_with_cache(self, core_model): original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) infeasible = 0 for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() try: room(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("y_") for v in core_model.solver.variables) assert any(c.name.startswith("room_const_") for c in core_model.solver.constraints) except OptimizationError: # TODO: room shouldn't return infeasible for non-essential reactions infeasible += 1 continue assert infeasible < len(core_model.reactions) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("y_") for v in core_model.solver.variables) assert not any(c.name.startswith("room_const_") for c in core_model.solver.constraints)
def test_room_with_cache(self, core_model): original_objective = core_model.objective pfba_solution = pfba(core_model) essential_reactions = find_essential_reactions(core_model) cache = ProblemCache(core_model) infeasible = 0 for r in core_model.reactions: if r not in essential_reactions: with core_model: r.knock_out() try: room(core_model, reference=pfba_solution, cache=cache) assert any(v.name.startswith("y_") for v in core_model.solver.variables) assert any(c.name.startswith("room_const_") for c in core_model.solver.constraints) except OptimizationError: # TODO: room shouldn't return infeasible for non-essential reactions infeasible += 1 continue assert infeasible < len(core_model.reactions) cache.reset() assert core_model.objective.expression == original_objective.expression assert not any(v.name.startswith("y_") for v in core_model.solver.variables) assert not any(c.name.startswith("room_const_") for c in core_model.solver.constraints)
def flux_analysis(sbml_file, seeds_file=None, targets_file=None, all_species=False): """ 1./ Run flux balance analyse with cobra package on an already defined reaction. Need to set in the sbml the value 'objective_coefficient' to 1. If the reaction is reachable by flux: return the flux value and the flux value for each reactant of the reaction. If not: only return the flux value for each reactant of the reaction. If a reactant has a flux of '0' this means that it is not reachable by flux (and maybe topologically). To unblock the reaction it is required to fix the metabolic network by adding/removing reactions until all reactant are reachable. 2./If seeds and targets given as sbml files with only compounds. Will also try to use the Menetools library to make a topologicall analysis. Topological reachabylity of the targets compounds from the seeds compounds. 3./ If --all_species: will test flux reachability of all the compounds in the metabolic network (may take several minutes) Parameters ---------- sbml_file: str path to sbml file to analyse seeds_file: str path to sbml file with only compounds representing the seeds/growth medium targets_file: str path to sbml file with only compounds representing the targets to reach all_species: bool if True will try to create obj function for each compound and return which are reachable by flux. """ if targets_file: if not os.path.exists(targets_file): raise FileNotFoundError("No target SBML file accessible at " + targets_file) targets = read_sbml_model(targets_file).metabolites if seeds_file: if not os.path.exists(seeds_file): raise FileNotFoundError("No seeds SBML file accessible at " + seeds_file) if not os.path.exists(sbml_file): raise FileNotFoundError("No target SBML file accessible at " + sbml_file) model = read_sbml_model(sbml_file) #nb metabolites real_metabolites = set( [i.id.replace("_" + i.compartment, "") for i in model.metabolites]) rxn_with_ga = [i for i in model.reactions if i.gene_reaction_rule] print("#############") print("Model summary") print("Number of compounds: %s" % len(real_metabolites)) print("Number of reactions: %s" % len(model.reactions)) print("Number of genes: %s" % len(model.genes)) print("Ratio rxn with genes/rxns: %s%%" % (100 * len(rxn_with_ga) / len(model.reactions))) # Launch a topoligical analysis if menetools is installed. if seeds_file and targets_file: print("#############") print("Analyzing targets") print("#Topological analysis") try: from menetools import run_menecheck menetools_result = run_menecheck(draft_sbml=sbml_file, seeds_sbml=seeds_file, targets_sbml=targets_file) print("Number of targets: %s" % (len(targets))) print("Unproductible targets: " + ",".join(menetools_result[0])) print("Productible targets: " + ",".join(menetools_result[1])) except ImportError: print( "Menetools is not installed. Can't run topological analysis.") print("#Flux Balance Analysis") fba_on_targets(targets, model) if all_species: targets = model.metabolites print( "#Flux Balance Analysis on all model metabolites (long process...)" ) fba_on_targets(targets, model) return try: biomassrxn = [ rxn for rxn in model.reactions if rxn.objective_coefficient == 1.0 ][0] biomassname = biomassrxn.id except IndexError: print( "Need to set OBJECTIVE COEFFICIENT to '1.0' for the reaction to test" ) exit() print("#############") print("Computing optimization") solution = model.optimize() print("Testing reaction %s" % biomassname) print("Growth rate: %s" % solution.objective_value) print("Status: %s" % solution.status) model.summary() if (solution.objective_value > 1e-5): blocked = cobra_flux_analysis.find_blocked_reactions( model, model.reactions) essRxns = cobra_flux_analysis.find_essential_reactions(model) essGenes = cobra_flux_analysis.find_essential_genes(model) print('FVA analysis:') print('\tBlocked reactions: %s' % len(blocked)) print('\tEssential reactions: %s' % len(essRxns)) [print(rxn.id) for rxn in essRxns] print('\tEssential genes: %s' % len(essGenes)) #get biomass rxn reactants bms_reactants = dict([(k, v) for k, v in list(biomassrxn.metabolites.items()) if v < 0]) bms_products = dict([(k, v) for k, v in list(biomassrxn.metabolites.items()) if v > 0]) dict_output = {"positive": {}, "negative": {}} #for each metabolite in reactant, create a biomass rxn with only this metabolite in reactants biomassrxn.objective_coefficient = 0.0 for reactant, stoich in list(bms_reactants.items()): test_rxn = Reaction("test_rxn") test_rxn.lower_bound = 0 test_rxn.upper_bound = 1000 metabolitedict = dict(bms_products) metabolitedict.update({reactant: stoich}) model.add_reactions([test_rxn]) test_rxn.add_metabolites(metabolitedict) test_rxn.objective_coefficient = 1.0 solution = model.optimize() if (solution.objective_value > 1e-5): dict_output["positive"][reactant] = solution.objective_value else: dict_output["negative"][reactant] = solution.objective_value model.remove_reactions([test_rxn]) print("%s/%s compounds with positive flux" % (len(list(dict_output["positive"].keys())), len(bms_reactants))) print("%s/%s compounds without flux" % (len(list(dict_output["negative"].keys())), len(bms_reactants))) for k, v in list(dict_output["positive"].items()): print("%s // %s %s positive" % (k, convert_from_coded_id(k.id)[0] + "_" + convert_from_coded_id(k.id)[2], v)) for k, v in list(dict_output["negative"].items()): print("%s // %s %s NULL" % (k, convert_from_coded_id(k.id)[0] + "_" + convert_from_coded_id(k.id)[2], v))