def maximize(self, is_pfba=False, growth=True): if is_pfba: if growth: try: return pfba(self.model).fluxes[self.biomass_reaction.id] except Infeasible: return 0 try: return pfba(self.model) except Infeasible: return Solution(objective_value=0, status='infeasible', fluxes=Series()) if growth: try: return self.model.optimize(objective_sense="maximize").objective_value except Infeasible: return 0 try: return self.model.optimize(objective_sense="maximize") except Infeasible: return Solution(objective_value=0, status='infeasible', fluxes=Series())
def test_metabolite_summary_interface(model, opt_solver): """Test that a summary can be created successfully.""" model.solver = opt_solver metabolite = model.metabolites.get_by_id("q8_c") MetaboliteSummary( metabolite=metabolite, model=model, ) MetaboliteSummary( metabolite=metabolite, model=model, solution=pfba(model), ) MetaboliteSummary( metabolite=metabolite, model=model, fva=0.95, ) MetaboliteSummary( metabolite=metabolite, model=model, fva=flux_variability_analysis( model, reaction_list=["CYTBD", "NADH16", "SUCDi"] ), )
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 runCobra( sim_type: str, rpsbml: rpSBML, objective_id: str, hidden_species: List[str] = [], fraction_coeff: float = 0.95, medium: pd.DataFrame = None, logger: Logger = getLogger(__name__) ) -> Tuple[cobra_solution, pd.DataFrame]: """Run Cobra to optimize model. :param sim_type: The type of simulation to use. Available simulation types include: fraction, fba, rpfba :param rpsbml: The model to analyse. :param objective_id: Overwrite the auto-generated id of the results (Default: None) :param hidden_species: List of species to mask (Optional). :param fraction_coeff: The fraction of the optimum. Used in pfba simulation (Default: 0.95). :param medium: A DataFrame describing medium composition (Optional). :param logger: A logger (Optional). :type sim_type: str :type rpsbml: rpSBML :type objective_id: str :type hidden_species: List[str] :type fraction_coeff: float :type medium: pd.DataFrame :type logger: Logger :return: Results of the simulation. :rtype: cobra.Solution """ cobraModel = build_cobra_model(rpsbml=rpsbml, objective_id=objective_id, hidden_species=hidden_species, logger=logger) if not cobraModel: return None if is_df_medium_defined(medium): cobraModel.medium = df_to_medium(medium) logger.debug('Medium modify') logger.debug(cobraModel.medium) cobra_results = None if sim_type.lower() == 'pfba': cobra_results = pfba(cobraModel, fraction_coeff) else: cobra_results = cobraModel.optimize(objective_sense='maximize', raise_error=True) logger.debug(cobra_results) # Minimal medium. logger.debug('Minimal medium') minimal_medium = build_minimal_medium(model=cobraModel, solution=cobra_results) logger.debug(minimal_medium) return cobra_results, minimal_medium
def simulate(self, overrideSimulProblem=None): """ This method preforms the phenotype simulation of the GeckoModel with the modifications present in the overrideSimulProblem. Args: overrideSimulProblem (overrideStoicSimulProblem): override simulation Problem Returns: GeckoSimulationResult: Returns an object with the steady-state flux distribution, protein concentrations and solver status. """ new_constraints = OrderedDict() if overrideSimulProblem is not None: new_constraints = overrideSimulProblem.get_modifications() if self.constraints is not None: new_constraints.update(self.constraints) with self.model: for rId in list(new_constraints.keys()): reac = self.model.reactions.get_by_id(rId) reac.bounds = (new_constraints.get(rId)[0] * GeckoConfigurations.SCALE_CONSTANT, new_constraints.get(rId)[1] * GeckoConfigurations.SCALE_CONSTANT) if self.method_simul == 'pFBA': solution = pfba(self.model) else: if self.minimize: solution = self.model.optimize(objective_sense="minimize") else: solution = self.model.optimize() status = solverStatus.UNKNOWN if solution.status == "optimal": status = solverStatus.OPTIMAL fluxDist = solution.fluxes fluxes, prots = {}, {} for k, v in fluxDist.items(): if k.startswith("draw_prot_"): prots[k[10:]] = v / GeckoConfigurations.SCALE_CONSTANT elif k.startswith("prot_"): prots[k[5:11]] = v / GeckoConfigurations.SCALE_CONSTANT else: fluxes[k] = v / GeckoConfigurations.SCALE_CONSTANT # for fixing the simulation errors during the optimization self.model._solver = copy(self.new_solver) return GeckoSimulationResult(self.model, solverStatus=status, ssFluxesDistrib=fluxes, protConcentrations=prots, overrideSimulProblem=overrideSimulProblem)
def evaluate_biomass_coupled_production( model: cobra.Model, production_id: str, biomass_id: str, carbon_source_id: str, ) -> Tuple[Optional[float], Optional[float]]: """ Evaluate the biomass coupled production levels in the specific conditions. Warnings -------- This function is expected to be called within a context since it modifies the model's objective. Parameters ---------- model : cobra.Model The constraint-based metabolic model of the production organism. production_id : str The identifier of the reaction representing production, for example, a demand reaction on the compound. biomass_id : str The identifier of the reaction representing biomass accumulation, i.e., growth. carbon_source_id : str The identifier of the reaction representing carbon uptake, for example, a glucose exchange reaction. Returns ------- tuple float or None The theoretical maximum growth rate if any. float or None The maximum biomass coupled product yield if any. """ bpcy = biomass_product_coupled_yield( biomass_id, production_id, carbon_source_id ) try: model.objective = biomass_id solution = pfba(model) growth = solution[biomass_id] except OptimizationError as error: logger.error( "Could not determine biomass coupled production due to a solver " "error. %r", error, ) growth = None bpc_yield = None else: try: bpc_yield = bpcy(model, solution, None) except ZeroDivisionError: logger.error("Division by zero in yield calculation.") bpc_yield = None return growth, bpc_yield
def test_model_summary_to_frame_previous_solution(model, opt_solver): """Test that the summary correctly uses an existing solution.""" model.solver = opt_solver solution = pfba(model) rxn = model.reactions.EX_glc__D_e solution.fluxes[rxn.id] = -123 summary = model.summary(solution=solution) assert summary.to_frame().at[rxn.id, "flux"] == 123
def capitulo_8(): file = open("resultados_capitulo_8.txt", "w") salmonella = cobra.test.create_test_model('salmonella') nominal = salmonella.optimize() loopless = loopless_solution(salmonella) import pandas df = pandas.DataFrame( dict(loopless=loopless.fluxes, nominal=nominal.fluxes)) df.plot.scatter(x='loopless', y='nominal') model = Model() model.add_metabolites([Metabolite(i) for i in "ABC"]) model.add_reactions( [Reaction(i) for i in ["EX_A", "DM_C", "v1", "v2", "v3"]]) model.reactions.EX_A.add_metabolites({"A": 1}) model.reactions.DM_C.add_metabolites({"C": -1}) model.reactions.v1.add_metabolites({"A": -1, "B": 1}) model.reactions.v2.add_metabolites({"B": -1, "C": 1}) model.reactions.v3.add_metabolites({"C": -1, "A": 1}) model.objective = 'DM_C' with model: add_loopless(model) solution = model.optimize() file.write("loopless solution: status = " + solution.status) file.write("\n") file.write("loopless solution flux: v3 = %.1f" % solution.fluxes["v3"]) file.write("\n") solution = pfba(model) file.write("parsimonious solution: status = " + solution.status) file.write("\n") file.write("loopless solution flux: v3 = %.1f" % solution.fluxes["v3"]) file.write("\n") model.reactions.v3.lower_bound = 1 with model: add_loopless(model) try: solution = model.optimize() except: file.write('model is infeasible') file.write("\n") solution = pfba(model) file.write("parsimonious solution: status = " + solution.status) file.write("\n") file.write("loopless solution flux: v3 = %.1f" % solution.fluxes["v3"]) file.write("\n") file.close()
def test_model_summary_interface(model, opt_solver): """Test that a summary can be created successfully.""" model.solver = opt_solver ModelSummary(model=model, ) ModelSummary( model=model, solution=pfba(model), ) ModelSummary( model=model, fva=0.95, ) ModelSummary( model=model, fva=flux_variability_analysis( model, reaction_list=["CYTBD", "NADH16", "SUCDi"]), )
def _generate( self, model: "Model", solution: Optional["Solution"], fva: Optional[Union[float, pd.DataFrame]], ) -> None: """ Prepare the data for the summary instance. Parameters ---------- model : cobra.Model The metabolic model for which to generate a metabolite summary. solution : cobra.Solution, optional A previous model solution to use for generating the summary. If ``None``, the summary method will generate a parsimonious flux distribution. fva : pandas.DataFrame or float, optional Whether or not to include flux variability analysis in the output. If given, `fva` should either be a previous FVA solution matching the model or a float between 0 and 1 representing the fraction of the optimum objective to be searched. """ super()._generate(model=model, solution=solution, fva=fva) if solution is None: logger.info("Generating new parsimonious flux distribution.") solution = pfba(model) if isinstance(fva, float): logger.info("Performing flux variability analysis.") fva = flux_variability_analysis( model, reaction_list=[self._reaction], fraction_of_optimum=fva, ) # Create the basic flux table. self._flux = pd.DataFrame( data={"flux": [solution[self._reaction.id]]}, index=[self._reaction.id], ) if fva is not None: self._flux = self._flux.join(fva)
def simulate(model, biomass_reaction, method, objective_id, objective_direction): if method not in METHODS: raise ValueError(f"Unsupported simulation method '{method}'") if objective_id: model.objective = model.reactions.get_by_id(objective_id) if objective_direction: model.objective_direction = objective_direction try: logger.info(f"Simulating model {model.id} with {method}") if method == "fba": solution = model.optimize(raise_error=True) elif method == "pfba": solution = pfba(model) elif method == "fva": # FIXME: accept list of relevant fva reactions to calculate solution = flux_variability_analysis(model) elif method == "pfba-fva": # FIXME: accept list of relevant fva reactions to calculate solution = flux_variability_analysis(model, fraction_of_optimum=1, pfba_factor=1.05) except OptimizationError as error: logger.info(f"Optimization Error: {error}") raise else: if method in ("fba", "pfba"): flux_distribution = solution.fluxes.to_dict() growth_rate = flux_distribution[biomass_reaction] elif method in ("fva", "pfba-fva"): df = solution.rename(index=str, columns={ "maximum": "upper_bound", "minimum": "lower_bound" }) for key in ["lower_bound", "upper_bound"]: df[key] = df[key].astype("float") flux_distribution = df.T.to_dict() growth_rate = flux_distribution[biomass_reaction]["upper_bound"] logger.info( f"Simulation was successful with growth rate {growth_rate}") return flux_distribution, growth_rate
def rp_pfba(rpsbml, reaction_id, coefficient=1.0, fraction_of_optimum=0.95, is_max=True, pathway_id='rp_pathway', objective_id=None, logger=None): """Run parsimonious FBA using a single objective :param reaction_id: The id of the reactions involved in the objective :param coefficient: The coefficient associated with the reactions id (Default: 1.0) :param fraction_of_optimum: Between 0.0 and 1.0 determining the fraction of optimum (Default: 0.95) :param is_max: Maximise or minimise the objective (Default: True) :param pathway_id: The id of the heterologous pathway (Default: rp_pathway) :param objective_id: Overwrite the default id (Default: None) :type reaction_id: str :type coefficient: float :type fraction_of_optimum: float :type is_max: bool :type pathway_id: str :type objective_id: str :return: Tuple with the results of the FBA and boolean indicating the success or failure of the function :rtype: tuple """ logger = logger or logging.getLogger(__name__) fbc_plugin = rpsbml.getModel().getPlugin('fbc') rpsbml.checklibSBML(fbc_plugin, 'Getting FBC package') objective_id = rpsbml.findCreateObjective([reaction_id], [coefficient], is_max, objective_id) # run the FBA rpsbml.checklibSBML(fbc_plugin.setActiveObjectiveId(objective_id), 'Setting active objective ' + str(objective_id)) cobraModel = rpsbml.convertToCobra() if not cobraModel: return 0.0, False cobra_results = pfba(cobraModel, fraction_of_optimum) rpsbml.addAnalysisResults(objective_id, cobra_results, pathway_id) return cobra_results.objective_value, rpsbml
def test_reaction_summary_interface(model, opt_solver): """Test that a summary can be created successfully.""" model.solver = opt_solver reaction = model.reactions.get_by_id("FUM") ReactionSummary( reaction=reaction, model=model, ) ReactionSummary( reaction=reaction, model=model, solution=pfba(model), ) ReactionSummary( reaction=reaction, model=model, fva=0.95, ) ReactionSummary( reaction=reaction, model=model, fva=flux_variability_analysis(model, reaction_list=["FUM"]), )
def _generate( self, model: "Model", solution: Optional["Solution"], fva: Optional[Union[float, pd.DataFrame]], ) -> None: """ Prepare the data for the summary instance. Parameters ---------- model : cobra.Model The metabolic model for which to generate a metabolite summary. solution : cobra.Solution, optional A previous model solution to use for generating the summary. If ``None``, the summary method will generate a parsimonious flux distribution. fva : pandas.DataFrame or float, optional Whether or not to include flux variability analysis in the output. If given, `fva` should either be a previous FVA solution matching the model or a float between 0 and 1 representing the fraction of the optimum objective to be searched. """ super()._generate(model=model, solution=solution, fva=fva) if solution is None: logger.info("Generating new parsimonious flux distribution.") solution = pfba(model) if isinstance(fva, float): logger.info("Performing flux variability analysis.") fva = flux_variability_analysis( model=model, reaction_list=[r.id for r in self._reactions], fraction_of_optimum=fva, ) # Create the basic flux table. flux = pd.DataFrame( data=[( r.id, solution[r.id], r.get_coefficient(self._metabolite.id), ) for r in self._reactions], columns=["reaction", "flux", "factor"], index=[r.id for r in self._reactions], ) # Scale fluxes by stoichiometric coefficient. flux["flux"] *= flux["factor"] if fva is not None: flux = flux.join(fva) view = flux[["flux", "minimum", "maximum"]] # Set fluxes below model tolerance to zero. flux[["flux", "minimum", "maximum"]] = view.where(view.abs() >= model.tolerance, 0) # Create the scaled compound flux. flux[["minimum", "maximum"]] = flux[["minimum", "maximum"]].mul(flux["factor"], axis=0) # Negative factors invert the minimum/maximum relationship. negative = flux["factor"] < 0 tmp = flux.loc[negative, "maximum"] flux.loc[negative, "maximum"] = flux.loc[negative, "minimum"] flux.loc[negative, "minimum"] = tmp # Add zero to turn negative zero into positive zero for nicer display later. flux[["flux", "minimum", "maximum"]] += 0 else: # Set fluxes below model tolerance to zero. flux.loc[flux["flux"].abs() < model.tolerance, "flux"] = 0 # Add zero to turn negative zero into positive zero for nicer display later. flux["flux"] += 0 # Create production table from producing fluxes or zero fluxes where the # metabolite is a product in the reaction. is_produced = (flux["flux"] > 0) | ((flux["flux"] == 0) & (flux["factor"] > 0)) if fva is not None: self.producing_flux = flux.loc[ is_produced, ["flux", "minimum", "maximum", "reaction"]].copy() else: self.producing_flux = flux.loc[is_produced, ["flux", "reaction"]].copy() production = self.producing_flux["flux"].abs() self.producing_flux["percent"] = production / production.sum() # Create consumption table from consuming fluxes or zero fluxes where the # metabolite is a substrate in the reaction. is_consumed = (flux["flux"] < 0) | ((flux["flux"] == 0) & (flux["factor"] < 0)) if fva is not None: self.consuming_flux = flux.loc[ is_consumed, ["flux", "minimum", "maximum", "reaction"]].copy() else: self.consuming_flux = flux.loc[is_consumed, ["flux", "reaction"]].copy() consumption = self.consuming_flux["flux"].abs() self.consuming_flux["percent"] = consumption / consumption.sum() self._flux = flux
def run_parsimonous(self, selected_solver): solution = pfba(self.model) solution.method = "fba" self.add_solution(solution)
def path(m, s, p, pathfolder, specialgroup, specialgroup_begin): # calculate pathways between two metabolites in a model # m: model, s: substrate ID, p: product ID,pathfolder: the folder to save the calculated pathways with m as model: # to avoid change of the original model substrate = model.metabolites.get_by_id(s) product = model.metabolites.get_by_id(p) if 'SK_' + s in model.reactions: # add sink reaction model.reactions.get_by_id('SK_' + s).bounds = (-10, 0) #rea=model.reactions.get_by_id('SK_' + s) # rea.lb=-10.0 # rea.ub=-10.0 else: model.add_boundary(substrate, type='sink') model.reactions.get_by_id('SK_' + s).bounds = (-10, 0) #model.add_boundary(substrate, type='sink', lb=10) if 'DM_' + p in model.reactions: demand = model.reactions.get_by_id('DM_' + p) # for special metabolites, change to a new demand reaction to produce acCOA, acACP etc if p[-5:-2] in specialgroup or p[0:3] in specialgroup_begin: demand.remove_from_model() # model.remove_reactions([demand]) demand = add_demand(model, product, specialgroup_begin) else: demand = add_demand(model, product, specialgroup_begin) model.objective = demand try: fluxes = pfba(model).fluxes except: metpair = [s, p, 'no solution'] else: # solution = pfba(model,fraction_of_optimum=0.5) #using fraction_of_optimum to get the backbone pathway without carbon fixation # but it reduces the rate of the input reaction even it is fixed at -10 # not work for AcCoA to pyr, as other compounds in reaction coa_c + 2.0 flxso_c + pyr_c <=> accoa_c + co2_c + 2.0 flxr_c # still need to be balanced # rate=solution.objective_value #not use this because it is the sum of the fluxes rate = model.reactions.get_by_id('DM_' + p).flux # sometimes the input flux is not equal to the upper bound influx = abs(model.reactions.get_by_id('SK_' + s).flux) # print(rate) if rate > 1e-6: # pathfile = open(pathfolder+ "/"+ s + "--" + p + ".txt", 'w') # save the pathway for checking # for r,v in fluxes.iteritems(): # if abs(v)>1e-6: # pathfile.write(r + '\t' + model.reactions.get_by_id(r).build_reaction_string() + '\t' + str(v) + '\n') # pathfile.close() sc = cnumber(substrate, specialgroup_begin) srd = reduction_degree(substrate, specialgroup_begin) pc = cnumber(product, specialgroup_begin) prd = reduction_degree(product, specialgroup_begin) cyield = rate * pc / sc / influx # calculate the carbon yield if prd == 0: cyieldrd = 0 else: cyieldrd = srd * pc / sc / prd metpair = [ s, substrate.formula, sc, srd, srd / sc, p, product.formula, pc, prd, prd / pc, rate, cyield, cyieldrd, cyieldrd - cyield ] else: metpair = "no path" return metpair
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
def simulate(self, objective=None, method=SimulationMethod.FBA, maximize=True, constraints=None, reference=None, scalefactor=None): ''' Simulates a phenotype when applying a set constraints using the specified method. :param dic objective: The simulation objective. If none, the model objective is considered. :param method: The SimulationMethod (FBA, pFBA, lMOMA, etc ...) :param boolean maximize: The optimization direction. :param dic constraints: A dictionary of constraints to be applied to the model. :param dic reference: A dictionary of reaction flux values. :param float scalefactor: A positive scaling factor for the solver. Default None. ''' if not objective: objective = self.model.objective elif isinstance(objective, dict) and len(objective) > 0: objective = next(iter(objective.keys())) simul_constraints = OrderedDict() if constraints: simul_constraints.update(constraints) if self.constraints: simul_constraints.update(self.constraints) if self.environmental_conditions: simul_constraints.update(self.environmental_conditions) with self.model as model: model.objective = objective for rxn in list(simul_constraints.keys()): reac = model.reactions.get_by_id(rxn) # constraints defined as a tuple (lower_bound, upper_bound) or as a single float value if isinstance(simul_constraints.get(rxn), tuple): reac.bounds = (simul_constraints.get( rxn)[0], simul_constraints.get(rxn)[1]) else: reac.bounds = (simul_constraints.get( rxn), simul_constraints.get(rxn)) # NOTE: If working directly over optlang use 'max' and 'min' # such is the case with pytfa.core.Model... need to find some workaround objective_sense = 'maximize' if maximize else 'minimize' if method == SimulationMethod.FBA: solution = model.optimize(objective_sense=objective_sense) elif method == SimulationMethod.pFBA: # make fraction_of_optimum a configurable parameter? solution = pfba(model) elif method == SimulationMethod.lMOMA or method == SimulationMethod.MOMA: s = None if not maximize: s = model.optimize(objective_sense=objective_sense) linear = True if method == SimulationMethod.lMOMA else False solution = moma(model, solution=s, linear=linear) elif method == SimulationMethod.ROOM: solution = room(model) # Special case in which only the simulation context is required without any simulation result elif method == SimulationMethod.NONE: solution = Solution(None, 'unknown', None) pass else: raise Exception( "Unknown method to perform the simulation.") status = self.__status_mapping[solution.status] result = SimulationResult(model, solution.objective_value, fluxes=solution.fluxes.to_dict(OrderedDict), status=status, envcond=self.environmental_conditions, model_constraints=self.constraints, simul_constraints=constraints, maximize=maximize) return result
def _generate( self, model: "Model", solution: Optional["Solution"], fva: Optional[Union[float, pd.DataFrame]], ) -> None: """ Prepare the data for the summary instance. Parameters ---------- model : cobra.Model The metabolic model for which to generate a metabolite summary. solution : cobra.Solution, optional A previous model solution to use for generating the summary. If ``None``, the summary method will generate a parsimonious flux distribution. fva : pandas.DataFrame or float, optional Whether or not to include flux variability analysis in the output. If given, `fva` should either be a previous FVA solution matching the model or a float between 0 and 1 representing the fraction of the optimum objective to be searched. """ super()._generate(model=model, solution=solution, fva=fva) coefficients = linear_reaction_coefficients(model) if solution is None: logger.info("Generating new parsimonious flux distribution.") solution = pfba(model) if isinstance(fva, float): logger.info("Performing flux variability analysis.") fva = flux_variability_analysis( model=model, reaction_list=model.boundary, fraction_of_optimum=fva, ) if coefficients: self._objective: Dict["Reaction", float] = { rxn.copy(): coef for rxn, coef in coefficients.items() } self._objective_value: float = sum( solution[rxn.id] * coef for rxn, coef in self._objective.items()) else: logger.warning( "Non-linear or non-reaction model objective. Falling back to minimal " "display.") self._objective = { Reaction(id="Expression", name="Expression"): float("nan") } self._objective_value: float = float("nan") self._boundary: List["Reaction"] = [ rxn.copy() for rxn in sorted(model.boundary, key=attrgetter("id")) ] self._boundary_metabolites: List["Metabolite"] = [ met.copy() for rxn in self._boundary for met in rxn.metabolites ] flux = pd.DataFrame( data=[ (rxn.id, met.id, rxn.get_coefficient(met.id), solution[rxn.id]) for rxn, met in zip(self._boundary, self._boundary_metabolites) ], columns=["reaction", "metabolite", "factor", "flux"], index=[r.id for r in self._boundary], ) # Scale fluxes by stoichiometric coefficient. flux["flux"] *= flux["factor"] if fva is not None: flux = flux.join(fva) view = flux[["flux", "minimum", "maximum"]] # Set fluxes below model tolerance to zero. flux[["flux", "minimum", "maximum"]] = view.where(view.abs() >= model.tolerance, 0) # Create the scaled compound flux. flux[["minimum", "maximum"]] = flux[["minimum", "maximum"]].mul(flux["factor"], axis=0) # Negative factors invert the minimum/maximum relationship. negative = flux["factor"] < 0 tmp = flux.loc[negative, "maximum"] flux.loc[negative, "maximum"] = flux.loc[negative, "minimum"] flux.loc[negative, "minimum"] = tmp # Add zero to turn negative zero into positive zero for nicer display later. flux[["flux", "minimum", "maximum"]] += 0 else: # Set fluxes below model tolerance to zero. flux.loc[flux["flux"].abs() < model.tolerance, "flux"] = 0 # Add zero to turn negative zero into positive zero for nicer display later. flux["flux"] += 0 # Create production table from producing fluxes or zero fluxes where the # metabolite is a product in the reaction. is_produced = (flux["flux"] > 0) | ((flux["flux"] == 0) & (flux["factor"] > 0)) if fva is not None: self.uptake_flux = flux.loc[ is_produced, ["flux", "minimum", "maximum", "reaction", "metabolite"]].copy( ) else: self.uptake_flux = flux.loc[ is_produced, ["flux", "reaction", "metabolite"]].copy() # Create consumption table from consuming fluxes or zero fluxes where the # metabolite is a substrate in the reaction. is_consumed = (flux["flux"] < 0) | ((flux["flux"] == 0) & (flux["factor"] < 0)) if fva is not None: self.secretion_flux = flux.loc[ is_consumed, ["flux", "minimum", "maximum", "reaction", "metabolite"]].copy( ) else: self.secretion_flux = flux.loc[ is_consumed, ["flux", "reaction", "metabolite"]].copy() self._flux = flux