def min_uptake_objective(model): objective = {} for r_id in model.get_exchange_reactions(): compounds = model.reactions[r_id].get_substrates() metabolite = model.metabolites[compounds[0]] formulas = metabolite.metadata['FORMULA'].split(';') weight = molecular_weight(formulas[0]) if weight is not None: objective['f_' + r_id] = weight return objective
def biomass_weight(biomass_id, coeffs, model): bio_weight = 0 for m_id, coeff in coeffs.items(): metabolite = model.metabolites[m_id] if 'FORMULA' in metabolite.metadata: formulae = metabolite.metadata['FORMULA'].split(';') met_weight = np.mean([molecular_weight(formula) for formula in formulae]) contribution = -coeff * met_weight bio_weight += contribution # print '\t'.join([biomass_id, m_id, str(met_weight), str(coeff), str(contribution)]) else: warn('Unable to normalize {} due to missing formula for {}:'.format(biomass_id, m_id)) break return bio_weight
def minimal_medium(model, exchange_reactions=None, direction=-1, min_mass_weight=False, min_growth=1, max_uptake=100, max_compounds=None, n_solutions=1, validate=True, abstol=1e-6): """ Minimal medium calculator. Determines the minimum number of medium components for the organism to grow. Notes: There are two options provided: * simply minimize the total number of components * minimize nutrients by molecular weight (as implemented by Zarecki et al, 2014) Args: model (CBModel): model exchange_reactions: list of exchange reactions (if not provided all model exchange reactions are used) direction (int): direction of uptake reactions (negative or positive, default: -1) min_mass_weight (bool): minimize by molecular weight of nutrients (default: False) min_growth (float): minimum growth rate (default: 1) max_uptake (float): maximum uptake rate (default: 100) max_compounds (int): limit maximum number of compounds (optional) n_solutions (int): enumerate multiple solutions (default: 1) validate (bool): validate solution using FBA (for debugging purposes, default: False) abstol (float): tolerance for detecting a non-zero exchange flux (default: 1e-6) Returns: list: minimal set of exchange reactions Solution: solution from solver """ # TODO: 2_program_MMsolverClone.prof if exchange_reactions is None: exchange_reactions = list(model.get_exchange_reactions()) solver = solver_instance(model) # TODO: 2_program_MMsolver.prof #bck_bounds = {r_id: (model.reactions[r_id].lb, model.reactions[r_id].ub) for r_id in exchange_reactions} if direction < 0: solver.set_lower_bounds( {r_id: -max_uptake for r_id in exchange_reactions}) else: solver.set_upper_bounds( {r_id: max_uptake for r_id in exchange_reactions}) solver.set_lower_bounds({model.biomass_reaction: min_growth}) #bck_bounds[model.biomass_reaction] = (model.reactions[model.biomass_reaction].lb, model.reactions[model.biomass_reaction].ub) for r_id in exchange_reactions: solver.add_variable('y_' + r_id, 0, 1, vartype=VarType.BINARY, update_problem=False) solver.update() for r_id in exchange_reactions: if direction < 0: solver.add_constraint('c_' + r_id, { r_id: 1, 'y_' + r_id: max_uptake }, '>', 0, update_problem=False) else: solver.add_constraint('c_' + r_id, { r_id: 1, 'y_' + r_id: -max_uptake }, '<', 0, update_problem=False) if max_compounds: lhs = {'y_' + r_id: 1 for r_id in exchange_reactions} solver.add_constraint('max_cmpds', lhs, '<', max_compounds, update_problem=False) solver.update() if min_mass_weight: objective = {} for r_id in exchange_reactions: if direction < 0: compounds = model.reactions[r_id].get_substrates() else: compounds = model.reactions[r_id].get_products() if len(compounds) > 1: warn('Multiple compounds in exchange reaction (ignored)') continue if len(compounds) == 0: warn('No compounds in exchange reaction (ignored)') continue metabolite = model.metabolites[compounds[0]] if 'FORMULA' not in metabolite.metadata: warn('No formula for compound (ignored)') continue formulas = metabolite.metadata['FORMULA'].split(';') if len(formulas) > 1: warn('Multiple formulas for compound') weight = molecular_weight(formulas[0]) objective['y_' + r_id] = weight else: objective = {'y_' + r_id: 1 for r_id in exchange_reactions} solution = solver.solve(objective, minimize=True) if solution.status != Status.OPTIMAL: # warn('No solution found') return None, solution medium = set(r_id for r_id in exchange_reactions if (direction < 0 and solution.values[r_id] < -abstol or direction > 0 and solution.values[r_id] > abstol)) if validate: validate_solution(model, medium, exchange_reactions, direction, min_growth, max_uptake) if n_solutions == 1: return medium, solution else: medium_list = [medium] solutions = [solution] for i in range(1, n_solutions): constr_id = 'iteration_{}'.format(i) previous_sol = {'y_' + r_id: 1 for r_id in medium} solver.add_constraint(constr_id, previous_sol, '<', len(previous_sol) - 1) solution = solver.solve(objective, minimize=True) if solution.status != Status.OPTIMAL: break medium = set( r_id for r_id in exchange_reactions if (direction < 0 and solution.values[r_id] < -abstol or direction > 0 and solution.values[r_id] > abstol)) medium_list.append(medium) solutions.append(solution) return medium_list, solutions
def minimal_medium(model, exchange_reactions=None, direction=-1, min_mass_weight=False, min_growth=1, max_uptake=100, max_compounds=None, n_solutions=1, validate=True, abstol=1e-6, warnings=True, use_pool=False, pool_gap=None, solver=None): """ Minimal medium calculator. Determines the minimum number of medium components for the organism to grow. Notes: There are two options provided: * simply minimize the total number of components * minimize nutrients by molecular weight (as implemented by Zarecki et al, 2014) Args: model (CBModel): model exchange_reactions: list of exchange reactions (if not provided all model exchange reactions are used) direction (int): direction of uptake reactions (negative or positive, default: -1) min_mass_weight (bool): minimize by molecular weight of nutrients (default: False) min_growth (float): minimum growth rate (default: 1) max_uptake (float): maximum uptake rate (default: 100) max_compounds (int): limit maximum number of compounds (optional) n_solutions (int): enumerate multiple solutions (default: 1) validate (bool): validate solution using FBA (for debugging purposes, default: False) abstol (float): tolerance for detecting a non-zero exchange flux (default: 1e-6) Returns: list: minimal set of exchange reactions Solution: solution from solver """ def warn_wrapper(message): if warnings: warn(message) if exchange_reactions is None: exchange_reactions = list(model.get_exchange_reactions()) if not solver: solver = solver_instance(model) persistent = True else: persistent = False solver.set_lower_bounds({model.biomass_reaction: min_growth}) for r_id in exchange_reactions: solver.add_variable('y_' + r_id, 0, 1, vartype=VarType.BINARY, update_problem=False, persistent=persistent) solver.update() for r_id in exchange_reactions: if direction < 0: solver.add_constraint('c_' + r_id, { r_id: 1, 'y_' + r_id: max_uptake }, '>', 0, update_problem=False, persistent=persistent) else: solver.add_constraint('c_' + r_id, { r_id: 1, 'y_' + r_id: -max_uptake }, '<', 0, update_problem=False, persistent=persistent) if max_compounds: lhs = {'y_' + r_id: 1 for r_id in exchange_reactions} solver.add_constraint('max_cmpds', lhs, '<', max_compounds, update_problem=False, persistent=persistent) solver.update() if min_mass_weight: objective = {} for r_id in exchange_reactions: if direction < 0: compounds = model.reactions[r_id].get_substrates() else: compounds = model.reactions[r_id].get_products() if len(compounds) > 1: warn_wrapper( 'Multiple compounds in exchange reaction (ignored)') continue if len(compounds) == 0: warn_wrapper('No compounds in exchange reaction (ignored)') continue metabolite = model.metabolites[compounds[0]] if 'FORMULA' not in metabolite.metadata: warn_wrapper('No formula for compound (ignored)') continue formulas = metabolite.metadata['FORMULA'].split(';') if len(formulas) > 1: warn_wrapper('Multiple formulas for compound') weight = molecular_weight(formulas[0]) objective['y_' + r_id] = weight else: objective = {'y_' + r_id: 1 for r_id in exchange_reactions} result, ret_sols = None, None if direction < 0: constraints = { r_id: (-max_uptake, model.reactions[r_id].ub) for r_id in exchange_reactions } else: constraints = { r_id: (model.reactions[r_id].lb, max_uptake) for r_id in exchange_reactions } if n_solutions == 1: solution = solver.solve(objective, minimize=True, constraints=constraints, get_values=exchange_reactions) if solution.status != Status.OPTIMAL: warn_wrapper('No solution found') result, ret_sols = None, solution else: medium = get_medium(solution, exchange_reactions, direction, abstol) if validate: validate_solution(model, medium, exchange_reactions, direction, min_growth, max_uptake) result, ret_sols = medium, solution elif use_pool: solutions = solver.solve(objective, minimize=True, constraints=constraints, get_values=exchange_reactions, pool_size=n_solutions, pool_gap=pool_gap) if solutions is None: result, ret_sols = [], [] else: media = [ get_medium(solution, exchange_reactions, direction, abstol) for solution in solutions ] result, ret_sols = media, solutions else: media = [] solutions = [] for i in range(0, n_solutions): if i > 0: constr_id = 'iteration_{}'.format(i) previous_sol = {'y_' + r_id: 1 for r_id in medium} solver.add_constraint(constr_id, previous_sol, '<', len(previous_sol) - 1) solution = solver.solve(objective, minimize=True, constraints=constraints, get_values=exchange_reactions) if solution.status != Status.OPTIMAL: break medium = get_medium(solution, exchange_reactions, direction, abstol) media.append(medium) solutions.append(solution) result, ret_sols = media, solutions if not persistent: solver.clean_up() return result, ret_sols
def minimal_medium(model, exchange_reactions=None, direction=-1, min_mass_weight=False, min_growth=1, max_uptake=100, max_compounds=None, n_solutions=1, validate=True, abstol=1e-6, warnings=True, use_pool=False, pool_gap=None, solver=None, milp=True): """ Minimal medium calculator. Determines the minimum number of medium components for the organism to grow. Notes: There are two options provided: * simply minimize the total number of components * minimize nutrients by molecular weight (as implemented by Zarecki et al, 2014) Args: model (CBModel): model exchange_reactions: list of exchange reactions (if not provided all model exchange reactions are used) direction (int): direction of uptake reactions (negative or positive, default: -1) min_mass_weight (bool): minimize by molecular weight of nutrients (default: False) min_growth (float): minimum growth rate (default: 1) max_uptake (float): maximum uptake rate (default: 100) max_compounds (int): limit maximum number of compounds (optional) n_solutions (int): enumerate multiple solutions (default: 1) validate (bool): validate solution using FBA (for debugging purposes, default: False) abstol (float): tolerance for detecting a non-zero exchange flux (default: 1e-6) Returns: list: minimal set of exchange reactions Solution: solution from solver """ def warn_wrapper(message): if warnings: warn(message) if exchange_reactions is None: exchange_reactions = model.get_exchange_reactions() if not solver: solver = solver_instance(model) persistent = True else: persistent = False if not milp and max_compounds is not None: raise RuntimeError("max_compounds can only be used with MILP formulation") if not milp and n_solutions > 1: raise RuntimeError("n_solutions can only be used with MILP formulation") if milp: for r_id in exchange_reactions: solver.add_variable('y_' + r_id, 0, 1, vartype=VarType.BINARY, update_problem=False, persistent=persistent) else: for r_id in exchange_reactions: solver.add_variable('f_' + r_id, 0, max_uptake, update_problem=False, persistent=persistent) solver.update() if milp: for r_id in exchange_reactions: if direction < 0: solver.add_constraint('c_' + r_id, {r_id: 1, 'y_' + r_id: max_uptake}, '>', 0, update_problem=False, persistent=persistent) else: solver.add_constraint('c_' + r_id, {r_id: 1, 'y_' + r_id: -max_uptake}, '<', 0, update_problem=False, persistent=persistent) if max_compounds: lhs = {'y_' + r_id: 1 for r_id in exchange_reactions} solver.add_constraint('max_cmpds', lhs, '<', max_compounds, update_problem=False, persistent=persistent) else: for r_id in exchange_reactions: if direction < 0: solver.add_constraint('c_' + r_id, {r_id: 1, 'f_' + r_id: 1}, '>', 0, update_problem=False, persistent=persistent) else: solver.add_constraint('c_' + r_id, {r_id: 1, 'f_' + r_id: -1}, '<', 0, update_problem=False, persistent=persistent) solver.update() valid_reactions = [] if min_mass_weight: objective = {} multiple_compounds =[] no_compounds = [] no_formula = [] multiple_formulas = [] invalid_formulas = [] for r_id in exchange_reactions: if direction < 0: compounds = model.reactions[r_id].get_substrates() else: compounds = model.reactions[r_id].get_products() if len(compounds) > 1: multiple_compounds.append(r_id) continue #TODO should not allow reaction to be used if len(compounds) == 0: no_compounds.append(r_id) continue #TODO should not allow reaction to be used metabolite = model.metabolites[compounds[0]] if 'FORMULA' not in metabolite.metadata: no_formula.append(metabolite.id) continue #TODO should not allow reaction to be used formulas = metabolite.metadata['FORMULA'].split(';') if len(formulas) > 1: multiple_formulas.append(metabolite.id) weight = molecular_weight(formulas[0]) if weight is None: invalid_formulas.append(metabolite.id) continue if milp: objective['y_' + r_id] = weight else: objective['f_' + r_id] = weight valid_reactions.append(r_id) if multiple_compounds: warn_wrapper("Reactions ignored (multiple compounds): " + ','.join(multiple_compounds)) if no_compounds: warn_wrapper("Reactions ignored (no compounds): " + ','.join(no_compounds)) if multiple_compounds: warn_wrapper("Compounds ignored (no formula): " + ','.join(no_formula)) if multiple_formulas: warn_wrapper("Coupounds with multiple formulas (using first): " + ','.join(multiple_formulas)) if invalid_formulas: warn_wrapper("Coupounds ignored (invalid formula): " + ','.join(invalid_formulas)) else: if milp: objective = {'y_' + r_id: 1 for r_id in exchange_reactions} else: objective = {'f_' + r_id: 1 for r_id in exchange_reactions} valid_reactions = exchange_reactions result, ret_sols = None, None if direction < 0: constraints = {r_id: (-max_uptake if r_id in valid_reactions else 0, model.reactions[r_id].ub) for r_id in exchange_reactions} else: constraints = {r_id: (model.reactions[r_id].lb, max_uptake if r_id in valid_reactions else 0) for r_id in exchange_reactions} constraints[model.biomass_reaction] = (min_growth, None) if n_solutions == 1: solution = solver.solve(objective, minimize=True, constraints=constraints, get_values=exchange_reactions) if solution.status != Status.OPTIMAL: warn_wrapper('No solution found') result, ret_sols = None, solution else: medium = get_medium(solution, exchange_reactions, direction, abstol) if validate: validate_solution(model, medium, exchange_reactions, direction, min_growth, max_uptake) result, ret_sols = medium, solution elif use_pool: solutions = solver.solve(objective, minimize=True, constraints=constraints, get_values=exchange_reactions, pool_size=n_solutions, pool_gap=pool_gap) if solutions is None: result, ret_sols = [], [] else: media = [get_medium(solution, exchange_reactions, direction, abstol) for solution in solutions] result, ret_sols = media, solutions else: media = [] solutions = [] for i in range(0, n_solutions): if i > 0: constr_id = 'iteration_{}'.format(i) previous_sol = {'y_' + r_id: 1 for r_id in medium} solver.add_constraint(constr_id, previous_sol, '<', len(previous_sol) - 1) solution = solver.solve(objective, minimize=True, constraints=constraints, get_values=exchange_reactions) if solution.status != Status.OPTIMAL: break medium = get_medium(solution, exchange_reactions, direction, abstol) media.append(medium) solutions.append(solution) result, ret_sols = media, solutions if not persistent: solver.clean_up() return result, ret_sols