def test_moma_sanity(self, model): """Test optimization criterion and optimality.""" try: solver = sutil.get_solver_name(qp=True) model.solver = solver except sutil.SolverNotFound: pytest.skip("no qp support") sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() ssq = (knock_sol.fluxes - sol.fluxes).pow(2).sum() with model: add_moma(model) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_ssq = (moma_sol.fluxes - sol.fluxes).pow(2).sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_ssq = (moma_ref_sol.fluxes - sol.fluxes).pow(2).sum() assert numpy.isclose(moma_sol.objective_value, moma_ssq) assert moma_ssq < ssq assert numpy.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert numpy.isclose(moma_ssq, moma_ref_ssq)
def test_moma_sanity(model: Model, qp_solvers: List[str]) -> None: """Test optimization criterion and optimality for MOMA.""" model.solver = qp_solvers sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() ssq = (knock_sol.fluxes - sol.fluxes).pow(2).sum() with model: add_moma(model, linear=False) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_ssq = (moma_sol.fluxes - sol.fluxes).pow(2).sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol, linear=False) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_ssq = (moma_ref_sol.fluxes - sol.fluxes).pow(2).sum() assert np.isclose(moma_sol.objective_value, moma_ssq) assert moma_ssq < ssq assert np.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert np.isclose(moma_ssq, moma_ref_ssq)
def test_single_gene_deletion_linear_moma(self, model): try: solver = sutil.get_solver_name(qp=True) model.solver = solver except sutil.SolverNotFound: pytest.skip("no qp support") # expected knockouts for textbook model growth_dict = { "b0008": 0.87, "b0114": 0.76, "b0116": 0.65, "b2276": 0.08, "b1779": 0.00 } result = single_gene_deletion(model, gene_list=growth_dict.keys(), method="linear moma")['growth'] assert all( abs(result[frozenset([gene])] - expected) < 0.01 for gene, expected in iteritems(growth_dict)) with model: add_moma(model, linear=True) with pytest.raises(ValueError): add_moma(model)
def test_moma_sanity(model, qp_solvers): """Test optimization criterion and optimality for MOMA.""" model.solver = qp_solvers sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() ssq = (knock_sol.fluxes - sol.fluxes).pow(2).sum() with model: add_moma(model, linear=False) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_ssq = (moma_sol.fluxes - sol.fluxes).pow(2).sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol, linear=False) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_ssq = (moma_ref_sol.fluxes - sol.fluxes).pow(2).sum() assert np.isclose(moma_sol.objective_value, moma_ssq) assert moma_ssq < ssq assert np.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert np.isclose(moma_ssq, moma_ref_ssq)
def test_moma_sanity(self, model): """Test optimization criterion and optimality.""" try: solver = sutil.get_solver_name(qp=True) model.solver = solver except sutil.SolverNotFound: pytest.skip("no qp support") sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() ssq = (knock_sol.fluxes - sol.fluxes).pow(2).sum() with model: add_moma(model) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_ssq = (moma_sol.fluxes - sol.fluxes).pow(2).sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_ssq = (moma_ref_sol.fluxes - sol.fluxes).pow(2).sum() assert numpy.isclose(moma_sol.objective_value, moma_ssq) assert moma_ssq < ssq assert numpy.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert numpy.isclose(moma_ssq, moma_ref_ssq)
def test_single_gene_deletion_moma(self, model): try: sutil.get_solver_name(qp=True) except sutil.SolverNotFound: pytest.skip("no qp support") # expected knockouts for textbook model growth_dict = { "b0008": 0.87, "b0114": 0.71, "b0116": 0.56, "b2276": 0.11, "b1779": 0.00 } df = single_gene_deletion(model, gene_list=growth_dict.keys(), method="moma") assert numpy.all([df.status == 'optimal']) assert all( abs(df.flux[gene] - expected) < 0.01 for gene, expected in iteritems(growth_dict)) with model: add_moma(model) with pytest.raises(ValueError): add_moma(model)
def test_linear_moma_sanity(self, model): """Test optimization criterion and optimality.""" sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() sabs = (knock_sol.fluxes - sol.fluxes).abs().sum() with model: add_moma(model, linear=True) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_sabs = (moma_sol.fluxes - sol.fluxes).abs().sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol, linear=True) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_sabs = (moma_ref_sol.fluxes - sol.fluxes).abs().sum() assert numpy.allclose(moma_sol.objective_value, moma_sabs) assert moma_sabs < sabs assert numpy.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert numpy.isclose(moma_sabs, moma_ref_sabs) with model: add_moma(model, linear=True) with pytest.raises(ValueError): add_moma(model)
def test_linear_moma_sanity(model: Model, all_solvers: List[str]) -> None: """Test optimization criterion and optimality for linear MOMA.""" model.solver = all_solvers sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() sabs = (knock_sol.fluxes - sol.fluxes).abs().sum() with model: add_moma(model, linear=True) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_sabs = (moma_sol.fluxes - sol.fluxes).abs().sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol, linear=True) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_sabs = (moma_ref_sol.fluxes - sol.fluxes).abs().sum() assert np.allclose(moma_sol.objective_value, moma_sabs) assert moma_sabs < sabs assert np.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert np.isclose(moma_sabs, moma_ref_sabs) with model: add_moma(model, linear=True) with pytest.raises(ValueError): add_moma(model)
def test_linear_moma_sanity(self, model): """Test optimization criterion and optimality.""" sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() sabs = (knock_sol.fluxes - sol.fluxes).abs().sum() with model: add_moma(model, linear=True) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_sabs = (moma_sol.fluxes - sol.fluxes).abs().sum() # Use normal FBA as reference solution. with model: add_moma(model, solution=sol, linear=True) model.reactions.PFK.knock_out() moma_ref_sol = model.optimize() moma_ref_sabs = (moma_ref_sol.fluxes - sol.fluxes).abs().sum() assert numpy.allclose(moma_sol.objective_value, moma_sabs) assert moma_sabs < sabs assert numpy.isclose(moma_sol.objective_value, moma_ref_sol.objective_value) assert numpy.isclose(moma_sabs, moma_ref_sabs) with model: add_moma(model, linear=True) with pytest.raises(ValueError): add_moma(model)
def test_linear_moma_sanity(self, model): """Test optimization criterion and optimality.""" sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() sabs = (knock_sol.fluxes - sol.fluxes).abs().sum() with model: add_moma(model, linear=True) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_sabs = (moma_sol.fluxes - sol.fluxes).abs().sum() assert numpy.allclose(moma_sol.objective_value, moma_sabs) assert moma_sabs < sabs
def test_single_gene_deletion_linear_moma(self, model): try: solver = sutil.get_solver_name(qp=True) model.solver = solver except sutil.SolverNotFound: pytest.skip("no qp support") # expected knockouts for textbook model growth_dict = {"b0008": 0.87, "b0114": 0.76, "b0116": 0.65, "b2276": 0.08, "b1779": 0.00} result = single_gene_deletion( model, gene_list=growth_dict.keys(), method="linear moma")['growth'] assert all(abs(result[frozenset([gene])] - expected) < 0.01 for gene, expected in iteritems(growth_dict)) with model: add_moma(model, linear=True) with pytest.raises(ValueError): add_moma(model)
def test_single_gene_deletion_linear_moma(self, model): # expected knockouts for textbook model growth_dict = { "b0008": 0.87, "b0114": 0.76, "b0116": 0.65, "b2276": 0.08, "b1779": 0.00 } df = single_gene_deletion(model, gene_list=growth_dict.keys(), method="linear moma") assert numpy.all([df.status == 'optimal']) assert all( abs(df.flux[gene] - expected) < 0.01 for gene, expected in iteritems(growth_dict)) with model: add_moma(model, linear=True) with pytest.raises(ValueError): add_moma(model)
def test_linear_moma_sanity(self, model): """Test optimization criterion and optimality.""" try: solver = sutil.get_solver_name(qp=True) model.solver = solver except sutil.SolverNotFound: pytest.skip("no qp support") sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() sabs = (knock_sol.fluxes - sol.fluxes).abs().sum() with model: add_moma(model, linear=True) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_sabs = (moma_sol.fluxes - sol.fluxes).abs().sum() assert numpy.allclose(moma_sol.objective_value, moma_sabs) assert moma_sabs < sabs
def test_linear_moma_sanity(self, model): """Test optimization criterion and optimality.""" try: solver = sutil.get_solver_name(qp=True) model.solver = solver except sutil.SolverNotFound: pytest.skip("no qp support") sol = model.optimize() with model: model.reactions.PFK.knock_out() knock_sol = model.optimize() sabs = (knock_sol.fluxes - sol.fluxes).abs().sum() with model: add_moma(model, linear=True) model.reactions.PFK.knock_out() moma_sol = model.optimize() moma_sabs = (moma_sol.fluxes - sol.fluxes).abs().sum() assert numpy.allclose(moma_sol.objective_value, moma_sabs) assert moma_sabs < sabs
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 _multi_deletion(model, entity, element_lists, method="fba", solution=None, processes=None, **kwargs): """ Provide a common interface for single or multiple knockouts. Parameters ---------- model : cobra.Model The metabolic model to perform deletions in. entity : 'gene' or 'reaction' The entity to knockout (``cobra.Gene`` or ``cobra.Reaction``). element_lists : list List of iterables ``cobra.Reaction``s or ``cobra.Gene``s (or their IDs) to be deleted. method: {"fba", "moma", "linear moma", "room", "linear room"}, optional Method used to predict the growth rate. solution : cobra.Solution, optional A previous solution to use as a reference for (linear) MOMA or ROOM. processes : int, optional The number of parallel processes to run. Can speed up the computations if the number of knockouts to perform is large. If not passed, will be set to the number of CPUs found. kwargs : Passed on to underlying simulation functions. Returns ------- pandas.DataFrame A representation of all combinations of entity deletions. The columns are 'growth' and 'status', where index : frozenset([str]) The gene or reaction identifiers that were knocked out. growth : float The growth rate of the adjusted model. status : str The solution's status. """ solver = sutil.interface_to_str(model.problem.__name__) if method == "moma" and solver not in sutil.qp_solvers: raise RuntimeError( "Cannot use MOMA since '{}' is not QP-capable." "Please choose a different solver or use FBA only.".format(solver)) if processes is None: processes = CONFIGURATION.processes with model: if "moma" in method: add_moma(model, solution=solution, linear="linear" in method) elif "room" in method: add_room(model, solution=solution, linear="linear" in method, **kwargs) args = set([frozenset(comb) for comb in product(*element_lists)]) processes = min(processes, len(args)) def extract_knockout_results(result_iter): result = pd.DataFrame([ (frozenset(ids), growth, status) for (ids, growth, status) in result_iter ], columns=['ids', 'growth', 'status']) result.set_index('ids', inplace=True) return result if processes > 1: worker = dict(gene=_gene_deletion_worker, reaction=_reaction_deletion_worker)[entity] chunk_size = len(args) // processes pool = multiprocessing.Pool( processes, initializer=_init_worker, initargs=(model,) ) results = extract_knockout_results(pool.imap_unordered( worker, args, chunksize=chunk_size )) pool.close() pool.join() else: worker = dict(gene=_gene_deletion, reaction=_reaction_deletion)[entity] results = extract_knockout_results(map( partial(worker, model), args)) return results
def single_reaction_deletion_moma(cobra_model, reaction_list, solver=None, **solver_args): """Sequentially knocks out each reaction in a model using MOMA. Not supposed to be called directly use `single_reactions_deletion(..., method="moma")` instead. Parameters ---------- reaction_list : iterable List of reaction 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}) """ # The same function can not be used because MOMA can not re-use the # same LP object. Problem re-use leads to incorrect solutions. # This is *not* true for optlang solvers! 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 reaction in reaction_list: with m: reaction.bounds = (0.0, 0.0) m.solver.optimize() status = m.solver.status status_dict[reaction.id] = status if status == OPTIMAL: growth = m.variables.moma_old_objective.primal else: growth = 0.0 growth_rate_dict[reaction.id] = growth else: for reaction in reaction_list: index = cobra_model.reactions.index(reaction) solution = moma.moma_knockout(moma_model, moma_objective, (index,), solver=solver, **solver_args) status_dict[reaction.id] = solution.status growth_rate_dict[reaction.id] = solution.f return growth_rate_dict, status_dict
def _multi_deletion(model, entity, element_lists, method="fba", processes=None): """ Provide a common interface for single or multiple knockouts. Parameters ---------- model : cobra.Model The metabolic model to perform deletions in. entity : 'gene' or 'reaction' The entity to knockout (``cobra.Gene`` or ``cobra.Reaction``). element_lists : list List of iterables ``cobra.Reaction``s or ``cobra.Gene``s (or their IDs) to be deleted. method: {"fba", "moma", "linear moma"}, optional Method used to predict the growth rate. processes : int, optional The number of parallel processes to run. Can speed up the computations if the number of knockouts to perform is large. If not passed, will be set to the number of CPUs found. Returns ------- pandas.DataFrame A representation of all combinations of entity deletions. The columns are 'growth' and 'status', where index : frozenset([str]) The gene or reaction identifiers that were knocked out. growth : float The growth rate of the adjusted model. status : str The solution's status. """ solver = sutil.interface_to_str(model.problem.__name__) if "moma" in method and solver not in sutil.qp_solvers: raise RuntimeError( "Cannot use MOMA since '{}' is not QP-capable." "Please choose a different solver or use FBA only.".format(solver)) if processes is None: try: processes = multiprocessing.cpu_count() except NotImplementedError: warn("Number of cores could not be detected - assuming 1.") processes = 1 with model: if "moma" in method: add_moma(model, linear="linear" in method) args = set([frozenset(comb) for comb in product(*element_lists)]) processes = min(processes, len(args)) def extract_knockout_results(result_iter): result = pd.DataFrame([ (frozenset(ids), growth, status) for (ids, growth, status) in result_iter ], columns=['ids', 'growth', 'status']) result.set_index('ids', inplace=True) return result if processes > 1: worker = dict(gene=_gene_deletion_worker, reaction=_reaction_deletion_worker)[entity] chunk_size = len(args) // processes pool = multiprocessing.Pool( processes, initializer=_init_worker, initargs=(model,) ) results = extract_knockout_results(pool.imap_unordered( worker, args, chunksize=chunk_size )) pool.close() pool.join() else: worker = dict(gene=_gene_deletion, reaction=_reaction_deletion)[entity] results = extract_knockout_results(map( partial(worker, model), args)) return results
def _multi_deletion(model, entity, element_lists, method="fba", num_jobs=None): """ Provide a common interface for single or multiple knockouts. Parameters ---------- model : cobra.Model The metabolic model to perform deletions in. entity : 'gene' or 'reaction' The entity to knockout (``cobra.Gene`` or ``cobra.Reaction``). element_lists : list List of iterables ``cobra.Reaction``s or ``cobra.Gene``s (or their IDs) to be deleted. method: {"fba", "moma", "linear moma"}, optional Method used to predict the growth rate. num_jobs : int, optional The number of parallel processes to run. Can speed up the computations if the number of knockouts to perform is large. If not passed, will be set to the number of CPUs found. Returns ------- pandas.DataFrame A representation of all combinations of entity deletions. The columns are 'growth' and 'status', where index : frozenset([str]) The gene or reaction identifiers that were knocked out. growth : float The growth rate of the adjusted model. status : str The solution's status. """ solver = sutil.interface_to_str(model.problem.__name__) if "moma" in method and solver not in sutil.qp_solvers: raise RuntimeError( "Cannot use MOMA since '{}' is not QP-capable." "Please choose a different solver or use FBA only.".format(solver)) if num_jobs is None: try: num_cpu = multiprocessing.cpu_count() except NotImplementedError: warn("Number of cores could not be detected - assuming 1.") num_cpu = 1 else: num_cpu = num_jobs with model: if "moma" in method: add_moma(model, linear="linear" in method) args = set([frozenset(comb) for comb in product(*element_lists)]) num_cpu = min(num_cpu, len(args)) def extract_knockout_results(result_iter): result = pd.DataFrame([(frozenset(ids), growth, status) for (ids, growth, status) in result_iter], columns=['ids', 'growth', 'status']) result.set_index('ids', inplace=True) return result if num_cpu > 1: num_cpu = min(num_cpu, len(args)) worker = dict(gene=_gene_deletion_worker, reaction=_reaction_deletion_worker)[entity] chunk_size = len(args) // num_cpu pool = multiprocessing.Pool(num_cpu, initializer=_init_worker, initargs=(model, )) results = extract_knockout_results( pool.imap_unordered(worker, args, chunksize=chunk_size)) pool.close() pool.join() else: worker = dict(gene=_gene_deletion, reaction=_reaction_deletion)[entity] results = extract_knockout_results( map(partial(worker, model), args)) return results
developedRxnsS2 = addDevelopedReactions(model, 's2', reactionsS2) # Compute baseline behavior print('3-HP Production, Baseline') baseline = model.optimize() baselineTargetFlux = baseline['3HP_SINK'] print(' Growth %f (core), %f (wt)' % (baseline[biomassCoreRxn.id], baseline[biomassWtRxn.id])) print(' Glucose %f -> 3HP %f' % (baseline['EX_glc__D_e'], baselineTargetFlux)) # Set up MOMA constraints if needed if method == 'moma': add_moma(model, solution=baseline) # Compute engineered behavior with pathway reactions enabled for rxn in pathwayRxns: rxn.lower_bound = -1000 rxn.upper_bound = 1000 print('3-HP Production, w/Synthetic Path') engineered = model.optimize() normalTargetFlux = engineered['3HP_SINK'] print(' Growth %f (core), %f (wt)' % (engineered[biomassCoreRxn.id], engineered[biomassWtRxn.id])) print(' Glucose %f -> 3HP %f' % (engineered['EX_glc__D_e'], normalTargetFlux))