Esempio n. 1
0
def check_solver_status(status: str = None, raise_error: bool = False) -> None:
    """Perform standard checks on a solver's status.

    Parameters
    ----------
    status: str, optional
        The status string obtained from the solver (default None).
    raise_error: bool, optional
        If True, raise error or display warning if False (default False).

    Returns
    -------
    None

    Warns
    -----
    UserWarning
        If `status` is not optimal and `raise_error` is set to True.

    Raises
    ------
    OptimizationError
        If `status` is None or is not optimal and `raise_error` is set to
        True.

    """
    if status == OPTIMAL:
        return None
    elif (status in has_primals) and not raise_error:
        warn(f"Solver status is '{status}'.", UserWarning)
    elif status is None:
        raise OptimizationError(
            "Model is not optimized yet or solver context has been switched.")
    else:
        raise OptimizationError(f"Solver status is '{status}'.")
Esempio n. 2
0
def check_solver_status(status, raise_error=False):
    """Perform standard checks on a solver's status."""
    if status == OPTIMAL:
        return
    elif (status in has_primals) and not raise_error:
        warn("solver status is '{}'".format(status), UserWarning)
    elif status is None:
        raise OptimizationError(
            "model was not optimized yet or solver context switched")
    else:
        raise OptimizationError("solver status is '{}'".format(status))
Esempio n. 3
0
 def _calc_fluxes(self, alg='fba', sampling_n=0):
     try:
         if sampling_n == 0:
             self.model.solver.problem.write(self.__class__.__name__ +
                                             '.lp')
             if alg == 'pfba':
                 solution = pfba(self.model)
             else:
                 solution = self.model.optimize()
             if solution.status == OPTIMAL:
                 reversible_fluxes = solution.fluxes
                 self.logger.info(
                     f"Optimal objective: {solution.objective_value:.2f}")
             else:
                 raise OptimizationError(solution.status)
         else:
             reversible_fluxes = sample(
                 self.model,
                 n=sampling_n,
                 thinning=10,
                 processes=multiprocessing.cpu_count()).mean(axis=0)
         irreversible_fluxes = {}
         for reaction, flux in reversible_fluxes.iteritems():
             if flux < 0:
                 irreversible_fluxes[reaction + '_b'] = -flux
             else:
                 irreversible_fluxes[reaction] = flux
         return Series(irreversible_fluxes.values(),
                       index=irreversible_fluxes.keys())
     except (AttributeError, SolverError, OptimizationError) as e:
         self.logger.error(f'{str(e).capitalize()}')
         return Series([], dtype=object)
Esempio n. 4
0
def crossover(community, sol, fluxes=False, pfba=False):
    """Get the crossover solution."""
    gcs = sol.members.growth_rate.drop("medium")
    com_growth = sol.growth_rate
    logger.info("Starting crossover...")
    with community as com:
        logger.info("constraining growth rates.")
        context = get_context(community)
        if context is not None:
            context(partial(reset_min_community_growth, com))
        reset_min_community_growth(com)
        com.variables.community_objective.lb = 0.0
        com.variables.community_objective.ub = com_growth + 1e-6
        com.objective = 1000.0 * com.variables.community_objective
        for sp in com.species:
            const = com.constraints["objective_" + sp]
            const.ub = gcs[sp]
        logger.info("finding closest feasible solution")
        s = com.optimize()
        if s is None:
            reset_solver(com)
            s = com.optimize()
        if s is not None:
            s = CommunitySolution(com, slim=not fluxes)
        for sp in com.species:
            com.constraints["objective_" + sp].ub = None
    if s is None:
        raise OptimizationError("crossover could not converge (status = %s)." %
                                community.solver.status)
    s.objective_value /= 1000.0
    return s
Esempio n. 5
0
def solve(community,
          fluxes=True,
          pfba=True,
          raise_error=False,
          atol=1e-6,
          rtol=1e-6):
    """Get all fluxes stratified by taxa."""
    community.solver.optimize()
    status = community.solver.status
    if status in good:
        if status != OPTIMAL:
            if raise_error:
                raise OptimizationError("solver returned the status %s." %
                                        status)
            else:
                logger.info("solver returned the status %s," % status +
                            " returning the solution anyway.")
        if fluxes and pfba:
            add_pfba_objective(community, atol, rtol)
            community.solver.optimize()
        if fluxes:
            sol = CommunitySolution(community)
        else:
            sol = CommunitySolution(community, slim=True)
        return sol
    logger.warning("solver encountered an error %s" % status)
    return None
Esempio n. 6
0
def optimize_with_retry(com, message="could not get optimum."):
    """Try to reset the solver."""
    sol = com.optimize()
    if sol is None:
        reset_solver(com)
        sol = com.optimize()
    if sol is None:
        raise OptimizationError(message)
    else:
        return sol.objective_value
Esempio n. 7
0
    def flux(self):
        """
        The flux value in the most recent solution.

        Flux is the primal value of the corresponding variable in the model.

        Warnings
        --------
        * Accessing reaction fluxes through a `Solution` object is the safer,
          preferred, and only guaranteed to be correct way. You can see how to
          do so easily in the examples.
        * Reaction flux is retrieved from the currently defined
          `self._model.solver`. The solver status is checked but there are no
          guarantees that the current solver state is the one you are looking
          for.
        * If you modify the underlying model after an optimization, you will
          retrieve the old optimization values.

        Raises
        ------
        RuntimeError
            If the underlying model was never optimized beforehand or the
            reaction is not part of a model.
        OptimizationError
            If the solver status is anything other than 'optimal'.
        AssertionError
            If the flux value is not within the bounds.

        Examples
        --------
        >>> import cobra.test
        >>> model = cobra.test.create_test_model("textbook")
        >>> solution = model.optimize()
        >>> model.reactions.PFK.flux
        7.477381962160283
        >>> solution.fluxes.PFK
        7.4773819621602833
        """
        try:
            check_solver_status(self._model.solver.status)
            return self.forward_variable.primal - self.reverse_variable.primal
        except AttributeError:
            raise RuntimeError("reaction '{}' is not part of a model".format(
                self.id))
        # Due to below all-catch, which sucks, need to reraise these.
        except (RuntimeError, OptimizationError) as err:
            raise_with_traceback(err)
        # Would love to catch CplexSolverError and GurobiError here.
        except Exception as err:
            raise_from(
                OptimizationError(
                    "Likely no solution exists. Original solver message: {}."
                    "".format(str(err))),
                err,
            )
Esempio n. 8
0
    def shadow_price(self):
        """
        The shadow price in the most recent solution.

        Shadow price is the dual value of the corresponding constraint in the
        model.

        Warnings
        --------
        * Accessing shadow prices through a `Solution` object is the safer,
          preferred, and only guaranteed to be correct way. You can see how to
          do so easily in the examples.
        * Shadow price is retrieved from the currently defined
          `self._model.solver`. The solver status is checked but there are no
          guarantees that the current solver state is the one you are looking
          for.
        * If you modify the underlying model after an optimization, you will
          retrieve the old optimization values.

        Raises
        ------
        RuntimeError
            If the underlying model was never optimized beforehand or the
            metabolite is not part of a model.
        OptimizationError
            If the solver status is anything other than 'optimal'.

        Examples
        --------
        >>> import cobra
        >>> import cobra.test
        >>> model = cobra.test.create_test_model("textbook")
        >>> solution = model.optimize()
        >>> model.metabolites.glc__D_e.shadow_price
        -0.09166474637510488
        >>> solution.shadow_prices.glc__D_e
        -0.091664746375104883
        """
        try:
            check_solver_status(self._model.solver.status)
            return self._model.constraints[self.id].dual
        except AttributeError:
            raise RuntimeError("metabolite '{}' is not part of a model".format(
                self.id))
        # Due to below all-catch, which sucks, need to reraise these.
        except (RuntimeError, OptimizationError) as err:
            raise_with_traceback(err)
        # Would love to catch CplexSolverError and GurobiError here.
        except Exception as err:
            raise_from(
                OptimizationError(
                    "Likely no solution exists. Original solver message: {}."
                    "".format(str(err))),
                err,
            )
Esempio n. 9
0
def check_solver_status(status, raise_error=False):
    """Perform standard checks on a solver's status."""
    if status == optlang.interface.OPTIMAL:
        return
    elif status == optlang.interface.INFEASIBLE and not raise_error:
        warn("solver status is '{}'".format(status), UserWarning)
    elif status is None:
        raise RuntimeError(
            "model was not optimized yet or solver context switched")
    else:
        raise OptimizationError("solver status is '{}'".format(status))
Esempio n. 10
0
def check_solver_status(status):
    """Perform standard checks on a solver's status."""
    if status == "optimal":
        return
    elif status == "infeasible":
        warn("solver status is '{}'".format(status), UserWarning)
    elif status is None:
        raise RuntimeError(
            "model was not optimized yet or solver context switched")
    else:
        raise OptimizationError("solver status is '{}'".format(status))
Esempio n. 11
0
    def flux(self) -> float:
        """Get flux value in the most recent solution.

        Flux is the primal value of the corresponding variable in the model.

        Warnings
        --------
        * Accessing reaction fluxes through a `Solution` object is the safer,
          preferred, and only guaranteed to be correct way. You can see how to
          do so easily in the examples.
        * Reaction flux is retrieved from the currently defined
          `self._model.solver`. The solver status is checked but there are no
          guarantees that the current solver state is the one you are looking
          for.
        * If you modify the underlying model after an optimization, you will
          retrieve the old optimization values.

        Raises
        ------
        RuntimeError
            If the underlying model was never optimized beforehand or the
            reaction is not part of a model.
        OptimizationError
            If the solver status is anything other than 'optimal'.
        AssertionError
            If the flux value is not within the bounds.

        """
        try:
            check_solver_status(self._model.solver.status)
            return self.forward_variable.primal - self.reverse_variable.primal
        except AttributeError:
            raise RuntimeError(f"Protein '{self.id}' is not part of a model.")
        # Due to below all-catch, which sucks, need to reraise these.
        except (RuntimeError, OptimizationError) as err:
            raise OptimizationError(err)
        # Would love to catch CplexSolverError and GurobiError here.
        except Exception as err:
            raise OptimizationError(
                f"Likely no solution exists. Original solver message: {err}."
            )
Esempio n. 12
0
def find_direct_metabolites(model, reaction, tolerance=1E-06):
    """
    Return list of possible direct biomass precursor metabolites.

    The term direct metabolites describes metabolites that are involved only
    in either transport and/or boundary reactions, AND the biomass reaction(s),
    but not in any purely metabolic reactions.

    Parameters
    ----------
    model : cobra.Model
        The metabolic model under investigation.
    reaction : cobra.Reaction
        The biomass reaction of the model under investigation.
    tolerance : float, optional
        Tolerance below which values will be regarded as zero.

    Returns
    -------
    list
        Metabolites that qualify as direct metabolites i.e. biomass precursors
        that are taken up to be consumed by the biomass reaction only.

    """
    biomass_rxns = set(helpers.find_biomass_reaction(model))
    tra_bou_bio_rxns = helpers.find_interchange_biomass_reactions(
        model, biomass_rxns)
    try:
        precursors = find_biomass_precursors(model, reaction)
        main_comp = helpers.find_compartment_id_in_model(model, 'c')
        ext_space = helpers.find_compartment_id_in_model(model, 'e')
    except KeyError:
        LOGGER.error("Failed to properly identify cytosolic and extracellular "
                     "compartments.")
        raise_with_traceback(
            KeyError("The cytosolic and/or extracellular "
                     "compartments could not be identified."))
    except RuntimeError:
        LOGGER.error("Failed to properly identify cytosolic and extracellular "
                     "compartments.")
        raise_with_traceback(
            RuntimeError("The cytosolic and/or extracellular "
                         "compartments could not be "
                         "identified."))
    else:
        tra_bou_bio_mets = [
            met for met in precursors
            if met.reactions.issubset(tra_bou_bio_rxns)
        ]
        rxns_of_interest = set([
            rxn for met in tra_bou_bio_mets for rxn in met.reactions
            if rxn not in biomass_rxns
        ])

    solution = model.optimize(raise_error=True)
    if np.isclose(solution.objective_value, 0, atol=tolerance):
        LOGGER.error("Failed to generate a non-zero objective value with "
                     "flux balance analysis.")
        raise OptimizationError(
            "The flux balance analysis on this model returned an "
            "objective value of zero. Make sure the model can "
            "grow! Check if the constraints are not too strict!")

    tra_bou_bio_fluxes = {r: solution[r.id] for r in rxns_of_interest}
    met_flux_sum = {m: 0 for m in tra_bou_bio_mets}

    return detect_false_positive_direct_metabolites(tra_bou_bio_mets,
                                                    biomass_rxns, main_comp,
                                                    ext_space,
                                                    tra_bou_bio_fluxes,
                                                    met_flux_sum)