Esempio n. 1
0
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)
Esempio n. 2
0
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])
Esempio n. 3
0
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)
Esempio n. 4
0
    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
Esempio n. 5
0
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
Esempio n. 6
0
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
        ])