def fva_prune(cobra_model, bm_rxn): ''' iteratively do FVA, remove all reactions with a max flux of 0, and remove the reaction with the smallest nonzero maximum flux until that causes the biomass flux to fall to 0 ''' # removing reactions happens in-place, so we need to make a copy of the # cobra model before altering it in any way cobra_net = cobra_model.copy() # do FVA to get maximum fluxes for every reaction fva_data = fva(cobra_net, loopless=True) # save the biomass flux separately to make sure it doesn't get to zero bm_rxn_flux = fva_data.loc[bm_rxn.id]['maximum'] while True: # remove all non-boundary reactions with a maximum flux of 0 no_flux_rxn_ids = fva_data[fva_data['maximum'] == 0].index boundary_rxn_ids = [rxn.id for rxn in cobra_net.boundary] ids_to_remove = [ rxn for rxn in no_flux_rxn_ids if rxn not in boundary_rxn_ids ] rxns_to_remove = [ cobra_net.reactions.get_by_id(rxn_id) for rxn_id in ids_to_remove ] cobra_net.remove_reactions(rxns_to_remove) # find remaining reaction with smallest maximum flux and remove it flux_bearers = fva_data[fva_data['maximum'] != 0]['maximum'] min_flux_rxn_id = flux_bearers.abs().idxmin() min_flux_rxn = cobra_net.reactions.get_by_id(min_flux_rxn_id) # if this reaction is the biomass reaction, we're clearly done pruning if min_flux_rxn.id == bm_rxn.id: break cobra_net.remove_reactions([min_flux_rxn]) # see if that made the network unsolvable; if so, add the reaction back # and exit the while loop fva_data = fva(cobra_net, loopless=True) bm_rxn_flux = fva_data.loc[bm_rxn.id]['maximum'] if bm_rxn_flux < 10e-10: cobra_net.add_reaction(min_flux_rxn) break # we kept all of the boundary reactions around until now; drop the ones # that have no flux # have to recreate fva_data first since we probably just added an essential # reaction back to the network after discovering that it was essential fva_data = fva(cobra_net, loopless=True) cobra_net.remove_reactions(fva_data[fva_data['maximum'] == 0].index) return (cobra_net)
def imat(model, expression_profile=None, low_cutoff=0.25, high_cutoff=0.85, epsilon=0.1, condition=None, normalization=or2min_and2max, fraction_of_optimum=0.99, objective=None, not_measured_value=None, *args, **kwargs): """ Integrative Metabolic Analysis Tool Parameters ---------- model: cobra.Model A constraint-based model expression_profile: ExpressionProfile The expression profile low_cutoff: number The cut off value for low expression values high_cutoff: number The cut off value for high expression values epsilon: float """ assert isinstance(model, Model) assert isinstance(expression_profile, ExpressionProfile) assert isinstance(high_cutoff, numbers.Number) assert isinstance(low_cutoff, numbers.Number) condition = expression_profile.conditions[0] if condition is None else condition not_measured_value = 0 if not_measured_value is None else not_measured_value reaction_profile = expression_profile.to_reaction_dict(condition, model, not_measured_value, normalization) y_variables = list() x_variables = list() constraints = list() try: with model: if objective is not None: model.objective = objective fva_res = fva(model, reactions=list(reaction_profile.keys()), fraction_of_optimum=fraction_of_optimum) for rid, expression in six.iteritems(reaction_profile): if expression >= high_cutoff: reaction = model.reactions.get_by_id(rid) y_pos = model.solver.interface.Variable("y_%s_pos" % rid, type="binary") y_neg = model.solver.interface.Variable("y_%s_neg" % rid, type="binary") y_variables.append([y_neg, y_pos]) pos_constraint = model.solver.interface.Constraint( reaction.flux_expression + y_pos * (fva_res["minimum"][rid] - epsilon), lb=fva_res["minimum"][rid], name="pos_highly_%s" % rid) neg_constraint = model.solver.interface.Constraint( reaction.flux_expression + y_neg * (fva_res["maximum"][rid] + epsilon), ub=fva_res["maximum"][rid], name="neg_highly_%s" % rid) constraints.extend([pos_constraint, neg_constraint]) elif expression < low_cutoff: reaction = model.reactions.get_by_id(rid) x = model.solver.interface.Variable("x_%s" % rid, type="binary") x_variables.append(x) pos_constraint = model.solver.interface.Constraint( (1 - x) * fva_res["maximum"][rid] - reaction.flux_expression, lb=0, name="x_%s_upper" % rid) neg_constraint = model.solver.interface.Constraint( (1 - x) * fva_res["minimum"][rid] - reaction.flux_expression, ub=0, name="x_%s_lower" % rid) constraints.extend([pos_constraint, neg_constraint]) for variable in x_variables: model.solver.add(variable) for variables in y_variables: model.solver.add(variables[0]) model.solver.add(variables[1]) for constraint in constraints: model.solver.add(constraint) objective = model.solver.interface.Objective(Add(*[(y[0] + y[1]) for y in y_variables]) + Add(*x_variables), direction="max") with model: model.objective = objective solution = model.optimize() return IMATResult(solution.fluxes, solution.f, reaction_profile, low_cutoff, high_cutoff, epsilon) finally: model.solver.remove([var for var in x_variables if var in model.solver.variables]) model.solver.remove([var for pair in y_variables for var in pair if var in model.solver.variables]) model.solver.remove([const for const in constraints if const in model.solver.constraints])
def production_envelope(model, reactions, objective=None, c_source=None, points=20, solver=None): """Calculate the objective value conditioned on all combinations of fluxes for a set of chosen reactions The production envelope can be used to analyze a models ability to produce a given compound conditional on the fluxes for another set of reaction, such as the uptake rates. The model is alternately optimize with respect to minimizing and maximizing the objective and record the obtained fluxes. Ranges to compute production is set to the effective bounds, i.e. the minimum / maximum fluxes that can be obtained given current reaction bounds. Parameters ---------- model : cobra.Model The model to compute the production envelope for. reactions : list or string A list of reactions, reaction identifiers or single reaction objective : string, dict, model.solver.interface.Objective The objective (reaction) to use for the production envelope. Use the model's current objective is left missing. c_source : cobra.Reaction or string A reaction or reaction identifier that is the source of carbon for computing carbon (mol carbon in output over mol carbon in input) and mass yield (gram product over gram output). Only objectives with a carbon containing input and output metabolite is supported. points : int The number of points to calculate production for. solver : string The solver to use - only here for consistency with older implementations (this argument will be removed in the future). The solver should be set using `model.solver` directly. Only optlang based solvers are supported. Returns ------- pandas.DataFrame A data frame with one row per evaluated point and - reaction id : one column per input reaction indicating the flux at each given point, - flux: the objective flux - carbon_yield: if carbon source is defined and the product is a single metabolite (mol carbon product per mol carbon feeding source) - _mass_yield: if carbon source is defined and the product is a single metabolite (gram product per 1 g of feeding source) - direction: the direction of the optimization. Only points that give a valid solution are returned. Examples -------- >>> import cobra.test >>> from cobra.flux_analysis import production_envelope >>> model = cobra.test.create_test_model("textbook") >>> production_envelope(model, ["EX_glc__D_e", "EX_o2_e"]) """ legacy, solver = sutil.choose_solver(model, solver) if legacy: raise ValueError('production_envelope is only implemented for optlang ' 'based solver interfaces.') reactions = model.reactions.get_by_any(reactions) objective = model.solver.objective if objective is None else objective with model: model.objective = objective carbon_io = _c_input_output(model, c_source) min_max = fva(model, reactions, fraction_of_optimum=0) grid = [ linspace(min_max.minimum[rxn.id], min_max.maximum[rxn.id], points, endpoint=True) for rxn in reactions ] grid_list = list(product(*grid)) result = _envelope_for_points(model, reactions, grid_list, carbon_io) return pd.DataFrame(result)
def run(self, model, media): """This function mutates model.""" # Select optimization solver model.solver = self.solver if self.solver == 'coinor_cbc': # Use all available processors model.solver.configuration.threads = -1 # If specified, make all reactions reversible if self.is_all_reversible: for rct in model.reactions: rct.upper_bound = self.MAX_BOUND rct.lower_bound = self.MAX_BOUND * -1 # Add custom bounds to reactions for rct_id, lb, ub in self.custom_bound_list: if rct_id in model.reactions: rct = model.reactions.get_by_id(rct_id) rct.lower_bound, rct.upper_bound = lb, ub # Filter out user specified genes to ko that are not in model. self.feature_ko_list = list(filter(lambda gene: gene in model.genes, self.feature_ko_list)) # Knockout specified genes if self.feature_ko_list: cobra.manipulation.delete_model_genes(model, self.feature_ko_list) for rct_id in self.reaction_ko_list: if rct_id in model.reactions: rct = model.reactions.get_by_id(rct_id) rct.lower_bound, rct.upper_bound = 0, 0 # Update exchange reaction variable bounds based on user # specified max uptakes. Add max uptake contraints. self.configure_media(model, media) # Set objective if self.target_reaction: model.objective = self.target_reaction # Set direction of the objective function, maximize by default. if self.is_minimize_objective: model.objective.direction = 'min' # Compute FBA solution if self.fba_type == 'pFBA': from cobra.flux_analysis import pfba fba_sol = pfba(model, fraction_of_optimum=self.fraction_of_optimum_pfba) elif self.fba_type == 'Loopless FBA': # Run CycleFreeFlux algorithm fba_sol = cobra.flux_analysis.loopless_solution(model) else: # Run vanilla FBA fba_sol = model.optimize() # If specified, compute FVA solution fva_sol = None if self.fva_type != 'Neither': from cobra.flux_analysis import flux_variability_analysis as fva fva_sol = fva(model, loopless=self.fva_type == 'Loopless FVA', fraction_of_optimum=self.fraction_of_optimum_fva) # If specified, simulate all single gene knockouts essential_genes = set() if self.is_single_ko: essential_genes = cobra.flux_analysis.variability. \ find_essential_genes(model, threshold=1e-11) # Convert COBRApy model to kbase format fba_builder = KBaseFBABuilder.from_cobra(self.output_id, model, fba_sol, media, self.workspace) kbase_fba_obj = fba_builder.with_cobra_fva_solution(fva_sol).build() # TODO: essential_genes to this object in cobrakbase return kbase_fba_obj, fva_sol, fba_sol, essential_genes
def production_envelope(model, reactions, objective=None, carbon_sources=None, points=20, threshold=None): """Calculate the objective value conditioned on all combinations of fluxes for a set of chosen reactions The production envelope can be used to analyze a model's ability to produce a given compound conditional on the fluxes for another set of reactions, such as the uptake rates. The model is alternately optimized with respect to minimizing and maximizing the objective and the obtained fluxes are recorded. Ranges to compute production is set to the effective bounds, i.e., the minimum / maximum fluxes that can be obtained given current reaction bounds. Parameters ---------- model : cobra.Model The model to compute the production envelope for. reactions : list or string A list of reactions, reaction identifiers or a single reaction. objective : string, dict, model.solver.interface.Objective, optional The objective (reaction) to use for the production envelope. Use the model's current objective if left missing. carbon_sources : list or string, optional One or more reactions or reaction identifiers that are the source of carbon for computing carbon (mol carbon in output over mol carbon in input) and mass yield (gram product over gram output). Only objectives with a carbon containing input and output metabolite is supported. Will identify active carbon sources in the medium if none are specified. points : int, optional The number of points to calculate production for. threshold : float, optional A cut-off under which flux values will be considered to be zero (default model.tolerance). Returns ------- pandas.DataFrame A data frame with one row per evaluated point and - reaction id : one column per input reaction indicating the flux at each given point, - carbon_source: identifiers of carbon exchange reactions A column for the maximum and minimum each for the following types: - flux: the objective flux - carbon_yield: if carbon source is defined and the product is a single metabolite (mol carbon product per mol carbon feeding source) - mass_yield: if carbon source is defined and the product is a single metabolite (gram product per 1 g of feeding source) Examples -------- >>> import cobra.test >>> from cobra.flux_analysis import production_envelope >>> model = cobra.test.create_test_model("textbook") >>> production_envelope(model, ["EX_glc__D_e", "EX_o2_e"]) """ reactions = model.reactions.get_by_any(reactions) objective = model.solver.objective if objective is None else objective data = dict() if carbon_sources is None: c_input = find_carbon_sources(model) else: c_input = model.reactions.get_by_any(carbon_sources) if c_input is None: data['carbon_source'] = None elif hasattr(c_input, 'id'): data['carbon_source'] = c_input.id else: data['carbon_source'] = ', '.join(rxn.id for rxn in c_input) threshold = normalize_cutoff(model, threshold) size = points ** len(reactions) for direction in ('minimum', 'maximum'): data['flux_{}'.format(direction)] = full(size, nan, dtype=float) data['carbon_yield_{}'.format(direction)] = full( size, nan, dtype=float) data['mass_yield_{}'.format(direction)] = full( size, nan, dtype=float) grid = pd.DataFrame(data) with model: model.objective = objective objective_reactions = list(sutil.linear_reaction_coefficients(model)) if len(objective_reactions) != 1: raise ValueError('cannot calculate yields for objectives with ' 'multiple reactions') c_output = objective_reactions[0] min_max = fva(model, reactions, fraction_of_optimum=0) min_max[min_max.abs() < threshold] = 0.0 points = list(product(*[ linspace(min_max.at[rxn.id, "minimum"], min_max.at[rxn.id, "maximum"], points, endpoint=True) for rxn in reactions])) tmp = pd.DataFrame(points, columns=[rxn.id for rxn in reactions]) grid = pd.concat([grid, tmp], axis=1, copy=False) add_envelope(model, reactions, grid, c_input, c_output, threshold) return grid
def imat(model, expression_profile=None, low_cutoff=0.25, high_cutoff=0.85, epsilon=0.1, condition=None, normalization=or2min_and2max, fraction_of_optimum=0.99, objective=None, not_measured_value=None, *args, **kwargs): """ Integrative Metabolic Analysis Tool Parameters ---------- model: cobra.Model A constraint-based model expression_profile: ExpressionProfile The expression profile low_cutoff: number The cut off value for low expression values high_cutoff: number The cut off value for high expression values epsilon: float """ assert isinstance(model, Model) assert isinstance(expression_profile, ExpressionProfile) assert isinstance(high_cutoff, numbers.Number) assert isinstance(low_cutoff, numbers.Number) condition = expression_profile.conditions[ 0] if condition is None else condition not_measured_value = 0 if not_measured_value is None else not_measured_value reaction_profile = expression_profile.to_reaction_dict( condition, model, not_measured_value, normalization) y_variables = list() x_variables = list() constraints = list() try: with model: if objective is not None: model.objective = objective fva_res = fva(model, reactions=list(reaction_profile.keys()), fraction_of_optimum=fraction_of_optimum) for rid, expression in six.iteritems(reaction_profile): if expression >= high_cutoff: reaction = model.reactions.get_by_id(rid) y_pos = model.solver.interface.Variable("y_%s_pos" % rid, type="binary") y_neg = model.solver.interface.Variable("y_%s_neg" % rid, type="binary") y_variables.append([y_neg, y_pos]) pos_constraint = model.solver.interface.Constraint( reaction.flux_expression + y_pos * (fva_res["minimum"][rid] - epsilon), lb=fva_res["minimum"][rid], name="pos_highly_%s" % rid) neg_constraint = model.solver.interface.Constraint( reaction.flux_expression + y_neg * (fva_res["maximum"][rid] + epsilon), ub=fva_res["maximum"][rid], name="neg_highly_%s" % rid) constraints.extend([pos_constraint, neg_constraint]) elif expression < low_cutoff: reaction = model.reactions.get_by_id(rid) x = model.solver.interface.Variable("x_%s" % rid, type="binary") x_variables.append(x) pos_constraint = model.solver.interface.Constraint( (1 - x) * fva_res["maximum"][rid] - reaction.flux_expression, lb=0, name="x_%s_upper" % rid) neg_constraint = model.solver.interface.Constraint( (1 - x) * fva_res["minimum"][rid] - reaction.flux_expression, ub=0, name="x_%s_lower" % rid) constraints.extend([pos_constraint, neg_constraint]) for variable in x_variables: model.solver.add(variable) for variables in y_variables: model.solver.add(variables[0]) model.solver.add(variables[1]) for constraint in constraints: model.solver.add(constraint) objective = model.solver.interface.Objective( Add(*[(y[0] + y[1]) for y in y_variables]) + Add(*x_variables), direction="max") with model: model.objective = objective solution = model.optimize() return IMATResult(solution.fluxes, solution.f, reaction_profile, low_cutoff, high_cutoff, epsilon) finally: model.solver.remove( [var for var in x_variables if var in model.solver.variables]) model.solver.remove([ var for pair in y_variables for var in pair if var in model.solver.variables ]) model.solver.remove([ const for const in constraints if const in model.solver.constraints ])