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}'.")
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))
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)
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
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
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
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, )
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, )
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))
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))
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}." )
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)