def _gene_knockout_computation(m: Model, gene_ids: List[str], expected_reaction_ids: List[str]) -> None: """Compute gene knockout.""" genes = [m.genes.get_by_id(i) for i in gene_ids] expected_reactions = { m.reactions.get_by_id(i) for i in expected_reaction_ids } removed1 = set(find_gene_knockout_reactions(m, genes)) removed2 = set(_find_gene_knockout_reactions_fast(m, genes)) assert removed1 == expected_reactions assert removed2 == expected_reactions delete_model_genes(m, gene_ids, cumulative_deletions=False) assert _get_removed(m) == expected_reaction_ids undelete_model_genes(m)
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 double_gene_deletion_moma(cobra_model, gene_list_1=None, gene_list_2=None, method='moma', single_deletion_growth_dict=None, solver='glpk', growth_tolerance=1e-8, error_reporting=None): """This will disable reactions for all gene pairs from gene_list_1 and gene_list_2 and then run simulations to optimize for the objective function. The contribution of each reaction to the objective function is indicated in cobra_model.reactions[:].objective_coefficient vector. NOTE: We've assumed that there is no such thing as a synthetic rescue with this modeling framework. cobra_model: a cobra.Model object gene_list_1: Is None or a list of genes. If None then both gene_list_1 and gene_list_2 are assumed to correspond to cobra_model.genes. gene_list_2: Is None or a list of genes. If None then gene_list_2 is assumed to correspond to gene_list_1. method: 'fba' or 'moma' to run flux balance analysis or minimization of metabolic adjustments. single_deletion_growth_dict: A dictionary that provides the growth rate information for single gene knock outs. This can speed up simulations because nonviable single deletion strains imply that all double deletion strains will also be nonviable. solver: 'glpk', 'gurobi', or 'cplex'. error_reporting: None or True growth_tolerance: float. The effective lower bound on the growth rate for a single deletion that is still considered capable of growth. Returns a dictionary of the gene ids in the x dimension (x) and the y dimension (y), and the growth simulation data (data). """ #BUG: Since this might be called from ppmap, the modules need to #be imported. Modify ppmap to take depfuncs from numpy import zeros nan = float('nan') from cobra.flux_analysis.single_deletion import single_deletion from cobra.manipulation import delete_model_genes, undelete_model_genes ##TODO: Use keywords instead if isinstance(cobra_model, dict): tmp_dict = cobra_model cobra_model = tmp_dict['cobra_model'] if 'gene_list_1' in tmp_dict: gene_list_1 = tmp_dict['gene_list_1'] if 'gene_list_2' in tmp_dict: gene_list_2 = tmp_dict['gene_list_2'] if 'method' in tmp_dict: method = tmp_dict['method'] if 'single_deletion_growth_dict' in tmp_dict: single_deletion_growth_dict = tmp_dict['single_deletion_growth_dict'] if 'solver' in tmp_dict: solver = tmp_dict['solver'] if 'error_reporting' in tmp_dict: error_reporting = tmp_dict['error_reporting'] else: cobra_model = cobra_model #this is a slow way to revert models. wt_model = cobra_model #NOTE: It may no longer be necessary to use a wt_model #due to undelete_model_genes if gene_list_1 is None: gene_list_1 = cobra_model.genes elif not hasattr(gene_list_1[0], 'id'): gene_list_1 = map(cobra_model.genes.get_by_id, gene_list_1) #Get default values to use if the deletions do not alter any reactions cobra_model.optimize(solver=solver) basal_f = cobra_model.solution.f if method.lower() == 'moma': wt_model = cobra_model.copy() combined_model = None single_gene_set = set(gene_list_1) if gene_list_2 is not None: if not hasattr(gene_list_2[0], 'id'): gene_list_2 = map(cobra_model.genes.get_by_id, gene_list_2) single_gene_set.update(gene_list_2) #Run the single deletion analysis to account for double deletions that #target the same gene and lethal deletions. We assume that there #aren't synthetic rescues. single_deletion_growth_dict = single_deletion(cobra_model, list(single_gene_set), method=method, solver=solver)[0] if gene_list_2 is None or gene_list_1 == gene_list_2: number_of_genes = len(gene_list_1) gene_list_2 = gene_list_1 deletion_array = zeros([number_of_genes, number_of_genes]) ##TODO: Speed up this triangular process #For the case where the contents of the lists are the same cut the work in half. #There might be a faster way to do this by using a triangular array function #in numpy #Populate the diagonal from the single deletion lists for i, the_gene in enumerate(gene_list_1): deletion_array[i, i] = single_deletion_growth_dict[the_gene.id] for i, gene_1 in enumerate(gene_list_1[:-1]): #TODO: Since there cannot be synthetic rescues we can assume #that the whole row for a lethal deletion #will be equal to that deletion. if single_deletion_growth_dict[gene_1.id] < growth_tolerance: tmp_solution = single_deletion_growth_dict[gene_1.id] for j in range(i+1, number_of_genes): deletion_array[j, i] = deletion_array[i, j] = tmp_solution else: for j, gene_2 in enumerate(gene_list_1[i+1:], i+1): if single_deletion_growth_dict[gene_2.id] < growth_tolerance: tmp_solution = single_deletion_growth_dict[gene_2.id] else: delete_model_genes(cobra_model, [gene_1, gene_2]) if cobra_model._trimmed: if method.lower() == 'fba': #Assumes that the majority of perturbations don't change #reactions which is probably false cobra_model.optimize(solver=solver, error_reporting=error_reporting) the_status = cobra_model.solution.status tmp_solution = cobra_model.solution.f elif method.lower() == 'moma': try: moma_solution = moma(wt_model, cobra_model, combined_model=combined_model, solver=solver) tmp_solution = float(moma_solution.pop('objective_value')) the_status = moma_solution.pop('status') combined_model = moma_solution.pop('combined_model') del moma_solution except: tmp_solution = nan the_status = 'failed' if the_status not in ['opt', 'optimal'] and \ error_reporting: print('%s / %s: %s status: %s'%(gene_1, gene_2, solver, the_status)) #Reset the model to orginial form. undelete_model_genes(cobra_model) else: tmp_solution = basal_f deletion_array[j, i] = deletion_array[i, j] = tmp_solution else: deletion_array = zeros([len(gene_list_1), len(gene_list_2)]) #Now deal with the case where the gene lists are different for i, gene_1 in enumerate(gene_list_1): if single_deletion_growth_dict[gene_1.id] <= 0: for j in range(len(gene_list_2)): deletion_array[i, j] = 0. else: for j, gene_2 in enumerate(gene_list_2): #Assume no such thing as a synthetic rescue if single_deletion_growth_dict[gene_2.id] <= growth_tolerance: tmp_solution = single_deletion_growth_dict[gene_2.id] else: delete_model_genes(cobra_model, [gene_1, gene_2]) if cobra_model._trimmed: if method.lower() == 'fba': cobra_model.optimize(solver=solver) tmp_solution = cobra_model.solution.f the_status = cobra_model.solution.status elif method.lower() == 'moma': try: moma_solution = moma(wt_model, cobra_model, combined_model=combined_model, solver=solver) tmp_solution = float(moma_solution.pop('objective_value')) the_status = moma_solution.pop('status') combined_model = moma_solution.pop('combined_model') del moma_solution except: tmp_solution = nan the_status = 'failed' if the_status not in ['opt', 'optimal'] and \ error_reporting: print('%s / %s: %s status: %s'%(repr(gene_1), repr(gene_2), solver, cobra_model.solution.status)) #Reset the model to wt form undelete_model_genes(cobra_model) else: tmp_solution = basal_f deletion_array[i, j] = tmp_solution if hasattr(gene_list_1, 'id'): gene_list_1 = [x.id for x in gene_list_1] if hasattr(gene_list_2, 'id'): gene_list_2 = [x.id for x in gene_list_2] return({'x': gene_list_1, 'y': gene_list_2, 'data': deletion_array})
def double_gene_deletion( cobra_model, gene_list_1=None, gene_list_2=None, method="fba", single_deletion_growth_dict=None, the_problem="return", solver="glpk", error_reporting=None, ): """This will disable reactions for all gene pairs from gene_list_1 and gene_list_2 and then run simulations to optimize for the objective function. The contribution of each reaction to the objective function is indicated in cobra_model.reactions[:].objective_coefficient vector. cobra_model: a cobra.Model object gene_list_1: Is None or a list of genes. If None then both gene_list_1 and gene_list_2 are assumed to correspond to cobra_model.genes. gene_list_2: Is None or a list of genes. If None then gene_list_2 is assumed to correspond to gene_list_1. method: 'fba' or 'moma' to run flux balance analysis or minimization of metabolic adjustments. single_deletion_growth_dict: A dictionary that provides the growth rate information for single gene knock outs. This can speed up simulations because nonviable single deletion strains imply that all double deletion strains will also be nonviable. the_problem: Is None, 'return', or an LP model object for the solver. solver: 'glpk', 'gurobi', or 'cplex'. error_reporting: None or True Returns a dictionary of the genes in the x dimension (x), the y dimension (y), and the growth simulation data (data). """ # BUG: Since this might be called from ppmap, the modules need to # be imported. Modify ppmap to take depfuncs from numpy import zeros, nan from cobra.flux_analysis.single_deletion import single_deletion from cobra.manipulation import initialize_growth_medium from cobra.manipulation import delete_model_genes, undelete_model_genes ##TODO: Use keywords instead if isinstance(cobra_model, dict): tmp_dict = cobra_model cobra_model = tmp_dict["cobra_model"] if "gene_list_1" in tmp_dict: gene_list_1 = tmp_dict["gene_list_1"] if "gene_list_2" in tmp_dict: gene_list_2 = tmp_dict["gene_list_2"] if "method" in tmp_dict: method = tmp_dict["method"] if "the_problem" in tmp_dict: the_problem = tmp_dict["the_problem"] if "single_deletion_growth_dict" in tmp_dict: single_deletion_growth_dict = tmp_dict["single_deletion_growth_dict"] if "solver" in tmp_dict: solver = tmp_dict["solver"] if "error_reporting" in tmp_dict: error_reporting = tmp_dict["error_reporting"] else: cobra_model = cobra_model # this is a slow way to revert models. wt_model = cobra_model # NOTE: It may no longer be necessary to use a wt_model # due to undelete_model_genes if gene_list_1 is None: gene_list_1 = cobra_model.genes elif not hasattr(gene_list_1[0], "id"): gene_list_1 = map(cobra_model.genes.get_by_id, gene_list_1) # Get default values to use if the deletions do not alter any reactions the_problem = cobra_model.optimize(the_problem=the_problem, solver=solver) basal_f = cobra_model.solution.f if method.lower() == "moma": wt_model = cobra_model.copy() the_problem = "return" combined_model = None single_gene_set = set(gene_list_1) if gene_list_2: if not hasattr(gene_list_2[0], "id"): gene_list_2 = map(cobra_model.genes.get_by_id, gene_list_2) single_gene_set.update(gene_list_2) # Run the single deletion analysis to account for double deletions that # target the same gene and lethal deletions. We assume that there # aren't synthetic rescues. single_deletion_growth_dict = single_deletion( cobra_model, list(single_gene_set), method=method, the_problem=the_problem, solver=solver, error_reporting=error_reporting, )[0] if gene_list_2 is None or gene_list_1 == gene_list_2: deletion_array = zeros([len(gene_list_1), len(gene_list_1)]) ##TODO: Speed up this triangular process # For the case where the contents of the lists are the same cut the work in half. # There might be a faster way to do this by using a triangular array function # in numpy # Populate the diagonal from the single deletion lists for i, the_gene in enumerate(gene_list_1): deletion_array[i, i] = single_deletion_growth_dict[the_gene.id] for i in range(len(gene_list_1) - 1): gene_1 = gene_list_1[i] # TODO: Since there cannot be synthetic rescues we can assume # that the whole row for a lethal deletion # will be equal to that deletion. if single_deletion_growth_dict[gene_1.id] <= 0: for j in range(i + 1, len(gene_list_1)): deletion_array[j, i] = deletion_array[i, j] = single_deletion_growth_dict[gene_2.id] else: for j in range(i + 1, len(gene_list_1)): if single_deletion_growth_dict[gene_1.id] <= 0: tmp_solution = single_deletion_growth_dict[gene_1.id] else: gene_2 = gene_list_1[j] delete_model_genes(cobra_model, [gene_1, gene_2]) if cobra_model._trimmed: if method.lower() == "fba": # Assumes that the majority of perturbations don't change # reactions which is probably false cobra_model.optimize( the_problem=the_problem, solver=solver, error_reporting=error_reporting ) the_status = cobra_model.solution.status tmp_solution = cobra_model.solution.f elif method.lower() == "moma": try: moma_solution = moma( wt_model, cobra_model, combined_model=combined_model, solver=solver, the_problem=the_problem, ) tmp_solution = float(moma_solution.pop("objective_value")) the_problem = moma_solution.pop("the_problem") the_status = moma_solution.pop("status") combined_model = moma_solution.pop("combined_model") del moma_solution except: tmp_solution = nan the_status = "failed" if the_status not in ["opt", "optimal"] and error_reporting: print "%s / %s: %s status: %s" % (gene_1, gene_2, solver, the_status) # Reset the model to orginial form. undelete_model_genes(cobra_model) else: tmp_solution = basal_f deletion_array[j, i] = deletion_array[i, j] = tmp_solution else: deletion_array = zeros([len(gene_list_1), len(gene_list_2)]) # Now deal with the case where the gene lists are different for i, gene_1 in enumerate(gene_list_1): if single_deletion_growth_dict[gene_1.id] <= 0: for j in range(len(gene_list_2)): deletion_array[i, j] = 0.0 else: for j, gene_2 in enumerate(gene_list_2): # Assume no such thing as a synthetic rescue if single_deletion_growth_dict[gene_2.id] <= 0: tmp_solution = single_deletion_growth_dict[gene_2.id] else: delete_model_genes(cobra_model, [gene_1, gene_2]) if cobra_model._trimmed: if method.lower() == "fba": cobra_model.optimize( the_problem=the_problem, solver=solver, error_reporting=error_reporting ) tmp_solution = cobra_model.solution.f the_status = cobra_model.solution.status elif method.lower() == "moma": try: moma_solution = moma( wt_model, cobra_model, combined_model=combined_model, solver=solver, the_problem=the_problem, ) tmp_solution = float(moma_solution.pop("objective_value")) the_problem = moma_solution.pop("the_problem") the_status = moma_solution.pop("status") combined_model = moma_solution.pop("combined_model") del moma_solution except: tmp_solution = nan the_status = "failed" if the_status not in ["opt", "optimal"] and error_reporting: print "%s / %s: %s status: %s" % ( repr(gene_1), repr(gene_2), solver, cobra_model.solution.status, ) # Reset the model to wt form undelete_model_genes(cobra_model) else: tmp_solution = basal_f deletion_array[i, j] = tmp_solution return {"x": gene_list_1, "y": gene_list_2, "data": deletion_array}
def double_gene_deletion_moma(cobra_model, gene_list_1=None, gene_list_2=None, method='moma', single_deletion_growth_dict=None, solver='glpk', growth_tolerance=1e-8, error_reporting=None): """This will disable reactions for all gene pairs from gene_list_1 and gene_list_2 and then run simulations to optimize for the objective function. The contribution of each reaction to the objective function is indicated in cobra_model.reactions[:].objective_coefficient vector. NOTE: We've assumed that there is no such thing as a synthetic rescue with this modeling framework. cobra_model: a cobra.Model object gene_list_1: Is None or a list of genes. If None then both gene_list_1 and gene_list_2 are assumed to correspond to cobra_model.genes. gene_list_2: Is None or a list of genes. If None then gene_list_2 is assumed to correspond to gene_list_1. method: 'fba' or 'moma' to run flux balance analysis or minimization of metabolic adjustments. single_deletion_growth_dict: A dictionary that provides the growth rate information for single gene knock outs. This can speed up simulations because nonviable single deletion strains imply that all double deletion strains will also be nonviable. solver: 'glpk', 'gurobi', or 'cplex'. error_reporting: None or True growth_tolerance: float. The effective lower bound on the growth rate for a single deletion that is still considered capable of growth. Returns a dictionary of the gene ids in the x dimension (x) and the y dimension (y), and the growth simulation data (data). """ #BUG: Since this might be called from ppmap, the modules need to #be imported. Modify ppmap to take depfuncs from numpy import zeros nan = float('nan') from cobra.flux_analysis.single_deletion import single_deletion from cobra.manipulation import delete_model_genes, undelete_model_genes ##TODO: Use keywords instead if isinstance(cobra_model, dict): tmp_dict = cobra_model cobra_model = tmp_dict['cobra_model'] if 'gene_list_1' in tmp_dict: gene_list_1 = tmp_dict['gene_list_1'] if 'gene_list_2' in tmp_dict: gene_list_2 = tmp_dict['gene_list_2'] if 'method' in tmp_dict: method = tmp_dict['method'] if 'single_deletion_growth_dict' in tmp_dict: single_deletion_growth_dict = tmp_dict[ 'single_deletion_growth_dict'] if 'solver' in tmp_dict: solver = tmp_dict['solver'] if 'error_reporting' in tmp_dict: error_reporting = tmp_dict['error_reporting'] else: cobra_model = cobra_model #this is a slow way to revert models. wt_model = cobra_model #NOTE: It may no longer be necessary to use a wt_model #due to undelete_model_genes if gene_list_1 is None: gene_list_1 = cobra_model.genes elif not hasattr(gene_list_1[0], 'id'): gene_list_1 = map(cobra_model.genes.get_by_id, gene_list_1) #Get default values to use if the deletions do not alter any reactions cobra_model.optimize(solver=solver) basal_f = cobra_model.solution.f if method.lower() == 'moma': wt_model = cobra_model.copy() combined_model = None single_gene_set = set(gene_list_1) if gene_list_2 is not None: if not hasattr(gene_list_2[0], 'id'): gene_list_2 = map(cobra_model.genes.get_by_id, gene_list_2) single_gene_set.update(gene_list_2) #Run the single deletion analysis to account for double deletions that #target the same gene and lethal deletions. We assume that there #aren't synthetic rescues. single_deletion_growth_dict = single_deletion(cobra_model, list(single_gene_set), method=method, solver=solver)[0] if gene_list_2 is None or gene_list_1 == gene_list_2: number_of_genes = len(gene_list_1) gene_list_2 = gene_list_1 deletion_array = zeros([number_of_genes, number_of_genes]) ##TODO: Speed up this triangular process #For the case where the contents of the lists are the same cut the work in half. #There might be a faster way to do this by using a triangular array function #in numpy #Populate the diagonal from the single deletion lists for i, the_gene in enumerate(gene_list_1): deletion_array[i, i] = single_deletion_growth_dict[the_gene.id] for i, gene_1 in enumerate(gene_list_1[:-1]): #TODO: Since there cannot be synthetic rescues we can assume #that the whole row for a lethal deletion #will be equal to that deletion. if single_deletion_growth_dict[gene_1.id] < growth_tolerance: tmp_solution = single_deletion_growth_dict[gene_1.id] for j in range(i + 1, number_of_genes): deletion_array[j, i] = deletion_array[i, j] = tmp_solution else: for j, gene_2 in enumerate(gene_list_1[i + 1:], i + 1): if single_deletion_growth_dict[ gene_2.id] < growth_tolerance: tmp_solution = single_deletion_growth_dict[gene_2.id] else: delete_model_genes(cobra_model, [gene_1, gene_2]) if cobra_model._trimmed: if method.lower() == 'fba': #Assumes that the majority of perturbations don't change #reactions which is probably false cobra_model.optimize( solver=solver, error_reporting=error_reporting) the_status = cobra_model.solution.status tmp_solution = cobra_model.solution.f elif method.lower() == 'moma': try: moma_solution = moma( wt_model, cobra_model, combined_model=combined_model, solver=solver) tmp_solution = float( moma_solution.pop('objective_value')) the_status = moma_solution.pop('status') combined_model = moma_solution.pop( 'combined_model') del moma_solution except: tmp_solution = nan the_status = 'failed' if the_status not in ['opt', 'optimal'] and \ error_reporting: print('%s / %s: %s status: %s' % (gene_1, gene_2, solver, the_status)) #Reset the model to orginial form. undelete_model_genes(cobra_model) else: tmp_solution = basal_f deletion_array[j, i] = deletion_array[i, j] = tmp_solution else: deletion_array = zeros([len(gene_list_1), len(gene_list_2)]) #Now deal with the case where the gene lists are different for i, gene_1 in enumerate(gene_list_1): if single_deletion_growth_dict[gene_1.id] <= 0: for j in range(len(gene_list_2)): deletion_array[i, j] = 0. else: for j, gene_2 in enumerate(gene_list_2): #Assume no such thing as a synthetic rescue if single_deletion_growth_dict[ gene_2.id] <= growth_tolerance: tmp_solution = single_deletion_growth_dict[gene_2.id] else: delete_model_genes(cobra_model, [gene_1, gene_2]) if cobra_model._trimmed: if method.lower() == 'fba': cobra_model.optimize(solver=solver) tmp_solution = cobra_model.solution.f the_status = cobra_model.solution.status elif method.lower() == 'moma': try: moma_solution = moma( wt_model, cobra_model, combined_model=combined_model, solver=solver) tmp_solution = float( moma_solution.pop('objective_value')) the_status = moma_solution.pop('status') combined_model = moma_solution.pop( 'combined_model') del moma_solution except: tmp_solution = nan the_status = 'failed' if the_status not in ['opt', 'optimal'] and \ error_reporting: print('%s / %s: %s status: %s' % (repr(gene_1), repr(gene_2), solver, cobra_model.solution.status)) #Reset the model to wt form undelete_model_genes(cobra_model) else: tmp_solution = basal_f deletion_array[i, j] = tmp_solution if hasattr(gene_list_1, 'id'): gene_list_1 = [x.id for x in gene_list_1] if hasattr(gene_list_2, 'id'): gene_list_2 = [x.id for x in gene_list_2] return ({'x': gene_list_1, 'y': gene_list_2, 'data': deletion_array})