def process_gene_knockout_solution(model, solution, simulation_method, simulation_kwargs, biomass, target, substrate, objective_function): """ Arguments --------- model: SolverBasedModel A constraint-based model solution: tuple The genes simulation_method: function See see cameo.flux_analysis.simulation simulation_kwargs: dict Keyword arguments to run the simulation method biomass: Reaction Cellular biomass reaction target: Reaction The strain design target substrate: Reaction The main carbon source uptake rate objective_function: cameo.strain_design.heuristic.evolutionary.objective_functions.ObjectiveFunction The objective function used for evaluation. Returns ------- list A list with: reactions, genes, size, fva_min, fva_max, target flux, biomass flux, yield, fitness """ with TimeMachine() as tm: genes = [model.genes.get_by_id(gid) for gid in solution] reactions = find_gene_knockout_reactions(model, solution) for reaction in reactions: reaction.knock_out(tm) reaction_ids = [r.id for r in reactions] flux_dist = simulation_method(model, reactions=objective_function.reactions, objective=biomass, **simulation_kwargs) tm(do=partial(setattr, model, "objective", biomass), undo=partial(setattr, model, "objective", model.objective)) fva = flux_variability_analysis(model, fraction_of_optimum=0.99, reactions=[target]) target_yield = flux_dist[target] / abs(flux_dist[substrate]) return [ tuple(reaction_ids), solution, len(solution), fva.lower_bound(target), fva.upper_bound(target), flux_dist[target], flux_dist[biomass], target_yield, objective_function(model, flux_dist, genes) ]
def _gene_deletion(model, ids): all_reactions = [] for g_id in ids: all_reactions.extend( find_gene_knockout_reactions(model, (model.genes.get_by_id(g_id), ))) _, growth, status = _reactions_knockouts_with_restore(model, all_reactions) return (ids, growth, status)
def visualize(self, index, map_name): if type == REACTION_KNOCKOUT_TYPE: knockouts = self.solutions[KNOCKOUTS][index] else: genes = [self.model.genes.get_by_id(g) for g in self.solutions[KNOCKOUTS][index]] knockouts = find_gene_knockout_reactions(self.model, genes) builder = draw_knockout_result(self.model, map_name, self.simulation_method, knockouts) return builder.display_in_notebook()
def _gene_deletion(model, ids): all_reactions = [] for g_id in ids: all_reactions.extend( find_gene_knockout_reactions( model, (model.genes.get_by_id(g_id),) ) ) _, growth, status = _reactions_knockouts_with_restore(model, all_reactions) return (ids, growth, status)
def run(gene_ids): ko_reactions = find_gene_knockout_reactions(cobra_model, gene_ids) ko_indexes = map(cobra_model.reactions.index, ko_reactions) # If all the reactions carry no flux, deletion will have no effect. if no_flux_reaction_indexes.issuperset(gene_ids): return wt_growth_rate return moma.moma_knockout(moma_model, moma_obj, ko_indexes, solver=solver, **kwargs).f
def simulate_knockout(self, to_knockout, *args, **kwargs): reactions = find_gene_knockout_reactions(self._model, [to_knockout]) cache = {"variables": {}, "constraints": {}, "first_run": True} with self._model: for reaction in reactions: reaction.knock_out() return self._simulation_method( self._model, volatile=False, cache=cache, *args, **kwargs)[cache['original_objective']]
def visualize(self, index, map_name): if type == REACTION_KNOCKOUT_TYPE: knockouts = self.solutions[KNOCKOUTS][index] else: genes = [ self.model.genes.get_by_id(g) for g in self.solutions[KNOCKOUTS][index] ] knockouts = find_gene_knockout_reactions(self.model, genes) builder = draw_knockout_result(self.model, map_name, self.simulation_method, knockouts) return builder.display_in_notebook()
def process_gene_knockout_solution(model, solution, simulation_method, simulation_kwargs, biomass, target, substrate, objective_function): """ Arguments --------- model: cobra.Model A constraint-based model solution: tuple The genes simulation_method: function See see cameo.flux_analysis.simulation simulation_kwargs: dict Keyword arguments to run the simulation method biomass: Reaction Cellular biomass reaction target: Reaction The strain design target substrate: Reaction The main carbon source uptake rate objective_function: cameo.strain_design.heuristic.evolutionary.objective_functions.ObjectiveFunction The objective function used for evaluation. Returns ------- list A list with: reactions, genes, size, fva_min, fva_max, target flux, biomass flux, yield, fitness """ with model: genes = [model.genes.get_by_id(gid) for gid in solution] reactions = find_gene_knockout_reactions(model, solution) for reaction in reactions: reaction.knock_out() reaction_ids = [r.id for r in reactions] flux_dist = simulation_method(model, reactions=objective_function.reactions, objective=biomass, **simulation_kwargs) model.objective = biomass fva = flux_variability_analysis(model, fraction_of_optimum=0.99, reactions=[target]) target_yield = flux_dist[target] / abs(flux_dist[substrate]) return [tuple(reaction_ids), solution, len(solution), fva.lower_bound(target), fva.upper_bound(target), flux_dist[target], flux_dist[biomass], target_yield, objective_function(model, flux_dist, genes)]
def simulate_knockout(self, to_knockout, *args, **kwargs): reactions = find_gene_knockout_reactions(self._model, [to_knockout]) cache = { "variables": {}, "constraints": {}, "first_run": True } with TimeMachine() as tm: for reaction in reactions: reaction.knock_out(tm) return self._simulation_method(self._model, volatile=False, cache=cache, *args, **kwargs)[cache['original_objective']]
def __call__(self, individual): """ Parameters ---------- individual : list a list of integers Returns ------- list [knockouts, decoded representation] """ genes = [self.model.genes.get_by_id(self.representation[index]) for index in individual] reactions = find_gene_knockout_reactions(self.model, genes) return [reactions, genes]
def gene_knockout_growth( gene_id, model, threshold=10 ** -6, simulation_method=fba, normalize=True, biomass=None, biomass_flux=None, *args, **kwargs ): if biomass_flux is None: s = model.solve() biomass_flux = s.f if "reference" not in kwargs: kwargs["reference"] = s.x_dict gene = model.genes.get_by_id(gene_id) knockouts = find_gene_knockout_reactions(model, [gene]) tm = TimeMachine() for reaction in knockouts: tm( do=partial(setattr, reaction, "lower_bound", 0), undo=partial(setattr, reaction, "lower_bound", reaction.lower_bound), ) tm( do=partial(setattr, reaction, "upper_bound", 0), undo=partial(setattr, reaction, "upper_bound", reaction.upper_bound), ) try: s = simulation_method(model, *args, **kwargs) f = s.get_primal_by_id(biomass) if f >= threshold: if normalize: f = f / biomass_flux else: f = 0 except SolveError: f = float("nan") finally: tm.reset() return f
def __call__(self, individual): """ Parameters ---------- individual : list a list of integers Returns ------- list [knockouts, decoded representation] """ genes = [ self.model.genes.get_by_id(self.representation[index]) for index in individual ] reactions = find_gene_knockout_reactions(self.model, genes) return [reactions, genes]
def gene_knockout_growth(gene_id, model, threshold=10**-6, simulation_method=fba, normalize=True, biomass=None, biomass_flux=None, *args, **kwargs): if biomass_flux is None: s = model.solve() biomass_flux = s.f if 'reference' not in kwargs: kwargs['reference'] = s.x_dict gene = model.genes.get_by_id(gene_id) knockouts = find_gene_knockout_reactions(model, [gene]) tm = TimeMachine() for reaction in knockouts: tm(do=partial(setattr, reaction, 'lower_bound', 0), undo=partial(setattr, reaction, 'lower_bound', reaction.lower_bound)) tm(do=partial(setattr, reaction, 'upper_bound', 0), undo=partial(setattr, reaction, 'upper_bound', reaction.upper_bound)) try: s = simulation_method(model, *args, **kwargs) f = s.get_primal_by_id(biomass) if f >= threshold: if normalize: f = f / biomass_flux else: f = 0 except SolveError: f = float('nan') finally: tm.reset() return f
def __call__(self, individual, flat=False): """ Parameters ---------- individual: list a list of integers flat: bool if True, returns strings. Otherwise returns Gene Returns ------- list [knockouts, decoded representation] """ genes = [self.model.genes.get_by_id(self.representation[index]) for index in individual] reactions = find_gene_knockout_reactions(self.model, genes) if flat: return [tuple(r.id for r in reactions), tuple(g.id for g in genes)] return [tuple(reactions), tuple(genes)]
def find_essential_genes_reactions(self): """ If the model has genes finds the reactions associated with the essential genes. Searches essential genes if hasn't done before. """ errors = [] try: if self.__essential_genes is not None: # Dict with reaction as key and list of genes as value reactions = {} for gene in self.__essential_genes: reactions_knock = find_gene_knockout_reactions( self.__cobra_model, [gene]) for reaction in reactions_knock: if reaction in reactions: reactions[reaction].append(gene) else: reactions[reaction] = [gene] self.__essential_genes_reactions = reactions except Exception as error: self.__essential_genes_reactions = {} errors.append(str(error)) return errors
def knock_out(self, time_machine=None): """Knockout gene by setting all its affected reactions' bounds to zero. Parameters ---------- time_machine = TimeMachine A time TimeMachine instance can be provided to undo the knockout eventually. Returns ------- None """ from cobra.manipulation.delete import find_gene_knockout_reactions for reaction in find_gene_knockout_reactions(self.model, [self]): def _(reaction, lb, ub): reaction.upper_bound = ub reaction.lower_bound = lb if time_machine is not None: time_machine(do=reaction.knock_out, undo=partial(_, reaction, reaction.lower_bound, reaction.upper_bound)) else: reaction.knock_out()
def _double_gene_deletion_fba(cobra_model, gene_ids1, gene_ids2, gene_id_to_result, solver, number_of_processes=None, zero_cutoff=1e-12, wt_growth_rate=None, no_flux_reaction_indexes=set(), **kwargs): """compute double gene deletions using fba cobra_model: model gene_ids1, gene_ids2: lists of id's to be knocked out gene_id_to_result: maps each gene identifier to the entry in the result matrix no_flux_reaction_indexes: set of indexes for reactions in the model which carry no flux in an optimal solution. For deletions only in this set, the result will beset to wt_growth_rate. returns an upper triangular square matrix """ # Because each gene reaction rule will be evaluated multiple times # the reaction has multiple associated genes being deleted, compiling # the gene reaction rules ahead of time increases efficiency greatly. compiled_rules = get_compiled_gene_reaction_rules(cobra_model) n_results = len(gene_id_to_result) results = numpy.empty((n_results, n_results)) results.fill(numpy.nan) if number_of_processes == 1: # explicitly disable multiprocessing PoolClass = CobraDeletionMockPool else: PoolClass = CobraDeletionPool with PoolClass(cobra_model, n_processes=number_of_processes, solver=solver, **kwargs) as pool: # precompute all single deletions in the pool and store them along # the diagonal for gene_id, gene_result_index in iteritems(gene_id_to_result): ko_reactions = find_gene_knockout_reactions( cobra_model, (cobra_model.genes.get_by_id(gene_id), )) ko_indexes = [cobra_model.reactions.index(i) for i in ko_reactions] pool.submit(ko_indexes, label=gene_result_index) for result_index, value in pool.receive_all(): # if singly lethal, set everything in row and column to 0 value = value if abs(value) > zero_cutoff else 0. if value == 0.: results[result_index, :] = 0. results[:, result_index] = 0. else: # only the diagonal needs to be set results[result_index, result_index] = value # Run double knockouts in the upper triangle index_selector = yield_upper_tria_indexes(gene_ids1, gene_ids2, gene_id_to_result) for result_index, (gene1, gene2) in index_selector: # if singly lethal the results have already been set if results[result_index] == 0: continue ko_reactions = find_gene_knockout_reactions( cobra_model, (gene1, gene2), compiled_rules) ko_indexes = [cobra_model.reactions.index(i) for i in ko_reactions] # if all removed gene indexes carry no flux if len(set(ko_indexes) - no_flux_reaction_indexes) == 0: results[result_index] = wt_growth_rate continue pool.submit(ko_indexes, label=result_index) for result in pool.receive_all(): value = result[1] if value < zero_cutoff: value = 0 results[result[0]] = value return results
def single_gene_deletion_fba(cobra_model, gene_list, solver=None, **solver_args): """Sequentially knocks out each gene in a model using FBA. Not supposed to be called directly use `single_reactions_deletion(..., method="fba")` instead. Parameters ---------- gene_list : iterable List of gene IDs or cobra.Reaction. solver: str, optional The name of the solver to be used. Returns ------- tuple of dicts A tuple ({reaction_id: growth_rate}, {reaction_id: status}) """ legacy = False if solver is None: solver = cobra_model.solver elif "optlang-" in solver: solver = solvers.interface_to_str(solver) solver = solvers.solvers[solver] else: legacy = True solver = legacy_solvers.solver_dict[solver] lp = solver.create_problem(cobra_model) growth_rate_dict = {} status_dict = {} if not legacy: with cobra_model as m: m.solver = solver for gene in gene_list: ko = find_gene_knockout_reactions(cobra_model, [gene]) with m: for reaction in ko: reaction.bounds = (0.0, 0.0) m.solver.optimize() status = m.solver.status status_dict[gene.id] = status growth_rate_dict[gene.id] = m.solver.objective.value if \ status == OPTIMAL else 0. else: for gene in gene_list: old_bounds = {} for reaction in find_gene_knockout_reactions(cobra_model, [gene]): index = cobra_model.reactions.index(reaction) old_bounds[index] = reaction.bounds solver.change_variable_bounds(lp, index, 0., 0.) solver.solve_problem(lp, **solver_args) # get the status and growth rate status = solver.get_status(lp) status_dict[gene.id] = status growth_rate = solver.get_objective_value(lp) \ if status == "optimal" else 0. growth_rate_dict[gene.id] = growth_rate # reset the problem for index, bounds in iteritems(old_bounds): solver.change_variable_bounds(lp, index, bounds[0], bounds[1]) return growth_rate_dict, status_dict
def single_gene_deletion_moma(cobra_model, gene_list, solver=None, **solver_args): """Sequentially knocks out each gene in a model using MOMA. Not supposed to be called directly use `single_reactions_deletion(..., method="moma")` instead. Parameters ---------- gene_list : iterable List of gene IDs or cobra.Reaction. solver: str, optional The name of the solver to be used. Returns ------- tuple of dicts A tuple ({reaction_id: growth_rate}, {reaction_id: status}) """ if moma is None: raise RuntimeError("scipy required for moma") legacy = False if solver is None: solver = cobra_model.solver elif "optlang-" in solver: solver = solvers.interface_to_str(solver) solver = solvers.solvers[solver] else: legacy = True solver = legacy_solvers.solver_dict[solver] moma_model, moma_objective = moma.create_euclidian_moma_model( cobra_model) growth_rate_dict = {} status_dict = {} if not legacy: with cobra_model as m: m.solver = solver moma.add_moma(m) for gene in gene_list: ko = find_gene_knockout_reactions(cobra_model, [gene]) with m: for reaction in ko: reaction.bounds = (0.0, 0.0) m.solver.optimize() status = m.solver.status status_dict[gene.id] = status if status == "optimal": growth = m.variables.moma_old_objective.primal else: growth = 0.0 growth_rate_dict[gene.id] = growth else: for gene in gene_list: delete_model_genes(moma_model, [gene.id]) solution = moma.solve_moma_model(moma_model, moma_objective, solver=solver, **solver_args) status_dict[gene.id] = solution.status growth_rate_dict[gene.id] = solution.f undelete_model_genes(moma_model) return growth_rate_dict, status_dict
def test_gene_knockout_decoder(self): decoder = GeneKnockoutDecoder([g.id for g in self.model.genes], self.model) reactions1, genes = decoder([1, 2, 3, 4]) reactions2 = find_gene_knockout_reactions(self.model, genes) self.assertTrue(sorted(reactions1, key=lambda x: x.id) == sorted(reactions2, key=lambda x: x.id))
def test_gene_knockout_decoder(self): decoder = GeneKnockoutDecoder([g.id for g in self.model.genes], self.model) reactions1, genes = decoder([1, 2, 3, 4]) reactions2 = find_gene_knockout_reactions(self.model, genes) self.assertTrue(sorted(reactions1, key=lambda x: x.id) == sorted(reactions2, key=lambda x: x.id))