Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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