def test_flux_variability_sequential_remove_cycles(self, core_model): original_objective = core_model.objective fva_solution = flux_variability_analysis( core_model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=SequentialView()) assert REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'] > 666. assert round(abs(fva_solution['upper_bound']['FRD7'] - 0.), 7) == 0 for key in fva_solution.data_frame.index: if REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key] > -666: assert abs(fva_solution['lower_bound'][key] - REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'] [key]) < 0.0001 if REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key] < 666: assert abs(fva_solution['upper_bound'][key] - REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'] [key]) < 0.0001 cycle_reac = cameo.Reaction("minus_PGI") # Create fake cycle cycle_reac.lower_bound = -1000 core_model.add_reaction(cycle_reac) cycle_reac.add_metabolites({ met: -c for met, c in core_model.reactions.PGI.metabolites.items() }) fva_solution = flux_variability_analysis(core_model, remove_cycles=False, reactions=["PGI"]) assert fva_solution.data_frame.loc["PGI", "upper_bound"] == 1000 fva_solution = flux_variability_analysis(core_model, remove_cycles=True, reactions=["PGI"]) assert fva_solution.data_frame.loc["PGI", "upper_bound"] < 666 assert original_objective == core_model.objective
def test_flux_variability_sequential(self, core_model): original_objective = core_model.objective fva_solution = flux_variability_analysis(core_model, fraction_of_optimum=0.999999419892, remove_cycles=False, view=SequentialView()) pfba_fva = flux_variability_analysis(core_model, fraction_of_optimum=1, pfba_factor=1).data_frame assert_data_frames_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE) assert_data_frames_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE) assert original_objective == core_model.objective assert sum(abs(pfba_fva.lower_bound)) - 518.422 < 0.001 assert sum(abs(pfba_fva.upper_bound)) - 518.422 < 0.001
def test_flux_variability_parallel(self, core_model): original_objective = core_model.objective mp_view = MultiprocessingView(2) fva_solution = flux_variability_analysis(core_model, fraction_of_optimum=0.999999419892, remove_cycles=False, view=mp_view) pfba_fva = flux_variability_analysis(core_model, fraction_of_optimum=1, pfba_factor=1, view=mp_view).data_frame mp_view.shutdown() assert_data_frames_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE) assert original_objective == core_model.objective assert sum(abs(pfba_fva.lower_bound)) - 518.422 < .001 assert sum(abs(pfba_fva.upper_bound)) - 518.422 < .001
def __call__(self, point): self._set_bounds(point[1]) return (point[1], flux_variability_analysis(self.model, reactions=self.included_reactions, remove_cycles=False, view=SequentialView()))
def fva(self) -> pd.DataFrame: model = self.read_model() result = fba(model) fluxes = result.fluxes try: fva_result = flux_variability_analysis( model, reactions=model.reactions, fraction_of_optimum=1.0 ) # type: FluxVariabilityResult df = fva_result.data_frame df_out = pd.DataFrame( { "model": self.model_path.name, "objective": self.objective_id, "reaction": df.index, "flux": fluxes, "status": CuratorConstants.STATUS_OPTIMAL, "minimum": df.lower_bound, "maximum": df.upper_bound, } ) except Exception as e: logger.error(f"{e}") df_out = pd.DataFrame( { "model": self.model_path.name, "objective": self.objective_id, "reaction": [r.id for r in model.reactions], "flux": fluxes, "status": CuratorConstants.STATUS_INFEASIBLE, "minimum": CuratorConstants.VALUE_INFEASIBLE, "maximum": CuratorConstants.VALUE_INFEASIBLE, } ) return df_out
def _process_knockouts(self): progress = ProgressBar( maxval=len(self._knockouts), widgets=["Processing solutions: ", Bar(), Percentage()]) self._processed_knockouts = DataFrame(columns=[ "reactions", "size", self._target, "biomass", "fva_min", "fva_max" ]) for i, knockouts in progress(enumerate(self._knockouts)): try: with self._model: [ self._model.reactions.get_by_id(ko).knock_out() for ko in knockouts ] fva = flux_variability_analysis(self._model, fraction_of_optimum=0.99, reactions=[self.target]) self._processed_knockouts.loc[i] = [ knockouts, len(knockouts), self.production[i], self.biomass[i], fva.lower_bound(self.target), fva.upper_bound(self.target) ] except OptimizationError: self._processed_knockouts.loc[i] = [ numpy.nan for _ in self._processed_knockouts.columns ]
def _remove_blocked_reactions(self): fva_res = flux_variability_analysis(self._model, fraction_of_optimum=0) blocked = [ self._model.reactions.get_by_id(reaction) for reaction, row in fva_res.data_frame.iterrows() if (round(row["lower_bound"], config.ndecimals) == round(row["upper_bound"], config.ndecimals) == 0)] self._model.remove_reactions(blocked)
def test_flux_variability_parallel(self): mp_view = MultiprocessingView() fva_solution = flux_variability_analysis(self.model, remove_cycles=False, view=mp_view) mp_view.shutdown() assert_dataframes_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE)
def __call__(self, point): self._set_bounds(point[1]) fva_result = flux_variability_analysis(self.model, reactions=self.included_reactions, remove_cycles=False, view=SequentialView()).data_frame fva_result['lower_bound'] = fva_result.lower_bound.apply(lambda v: 0 if abs(v) < non_zero_flux_threshold else v) fva_result['upper_bound'] = fva_result.upper_bound.apply(lambda v: 0 if abs(v) < non_zero_flux_threshold else v) return point[1], fva_result
def test_flux_variability_sequential(self): fva_solution = flux_variability_analysis(self.model, fraction_of_optimum=0.999999419892, remove_cycles=False, view=SequentialView()) assert_data_frames_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE) for key in fva_solution.data_frame.index: self.assertAlmostEqual(fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.00001) self.assertAlmostEqual(fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.00001) assert_data_frames_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE)
def test_flux_variability_sequential(self): fva_solution = flux_variability_analysis(self.model, fraction_of_optimum=0.999999419892, remove_cycles=False, view=SequentialView()) assert_dataframes_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE) for key in fva_solution.data_frame.index: self.assertAlmostEqual(fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.00001) self.assertAlmostEqual(fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.00001) assert_dataframes_equal(fva_solution, REFERENCE_FVA_SOLUTION_ECOLI_CORE)
def test_flux_variability_parallel_remove_cycles(self): fva_solution = flux_variability_analysis(self.model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=MultiprocessingView()) self.assertGreater(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'], 666.) self.assertAlmostEqual(fva_solution['upper_bound']['FRD7'], 0.) for key in fva_solution.data_frame.index: if REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key] > -666: self.assertAlmostEqual(fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.0001) if REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key] < 666: self.assertAlmostEqual(fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.0001)
def test_flux_variability_parallel_remove_cycles(self): fva_solution = flux_variability_analysis(self.model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=MultiprocessingView()) self.assertGreater(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'], 1000.) self.assertAlmostEqual(fva_solution['upper_bound']['FRD7'], 0.) for key in fva_solution.data_frame.index: if abs(REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key]) < 1000: self.assertAlmostEqual(fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.0001) if abs(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key]) < 1000: self.assertAlmostEqual(fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.0001)
def test_flux_variability_sequential_remove_cycles(self): fva_solution = flux_variability_analysis(self.model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=SequentialView()) self.assertGreater(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'], 666.) self.assertAlmostEqual(fva_solution['upper_bound']['FRD7'], 0.) for key in fva_solution.data_frame.index: if REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key] > -666: self.assertAlmostEqual(fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.0001) if REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key] < 666: self.assertAlmostEqual(fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.0001) cycle_reac = cameo.Reaction("minus_PGI") # Create fake cycle cycle_reac.lower_bound = -1000 self.model.add_reaction(cycle_reac) cycle_reac.add_metabolites({met: -c for met, c in self.model.reactions.PGI.metabolites.items()}) fva_solution = flux_variability_analysis(self.model, remove_cycles=False, reactions=["PGI"]) self.assertEqual(fva_solution.data_frame.loc["PGI", "upper_bound"], 1000) fva_solution = flux_variability_analysis(self.model, remove_cycles=True, reactions=["PGI"]) self.assertTrue(fva_solution.data_frame.loc["PGI", "upper_bound"] < 666)
def test_flux_variability_sequential_remove_cycles(self): fva_solution = flux_variability_analysis(self.model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=SequentialView()) self.assertGreater(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'], 666.) self.assertAlmostEqual(fva_solution['upper_bound']['FRD7'], 0.) for key in fva_solution.data_frame.index: if abs(REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key]) > -666: self.assertAlmostEqual(fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.0001) if abs(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key]) < 666: self.assertAlmostEqual(fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.0001) cycle_reac = cameo.Reaction("minus_PGI") # Create fake cycle cycle_reac.lower_bound = -1000 self.model.add_reaction(cycle_reac) cycle_reac.add_metabolites({met: -c for met, c in self.model.reactions.PGI.metabolites.items()}) fva_solution = flux_variability_analysis(self.model, remove_cycles=False, reactions=["PGI"]) self.assertEqual(fva_solution.data_frame.loc["PGI", "upper_bound"], 1000) fva_solution = flux_variability_analysis(self.model, remove_cycles=True, reactions=["PGI"]) self.assertTrue(fva_solution.data_frame.loc["PGI", "upper_bound"] < 666)
def test_flux_variability_parallel_remove_cycles(self, core_model): original_objective = core_model.objective fva_solution = flux_variability_analysis(core_model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=MultiprocessingView()) assert REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'] > 666. assert round(abs(fva_solution['upper_bound']['FRD7'] - 0.), 7) == 0 for key in fva_solution.data_frame.index: if REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key] > -666: assert abs( fva_solution['lower_bound'][key] - REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key]) < 0.0001 if REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key] < 666: assert abs( fva_solution['upper_bound'][key] - REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key]) < 0.0001 assert original_objective == core_model.objective
def _process_knockouts(self): progress = ProgressBar(maxval=len(self._designs), widgets=["Processing solutions: ", Bar(), Percentage()]) self._processed_knockouts = DataFrame(columns=["reactions", "size", self._target, "biomass", "fva_min", "fva_max"]) for i, knockouts in progress(enumerate(self._designs)): try: with TimeMachine() as tm: [self._model.reactions.get_by_id(ko).knock_out(time_machine=tm) for ko in knockouts] fva = flux_variability_analysis(self._model, fraction_of_optimum=0.99, reactions=[self.target]) self._processed_knockouts.loc[i] = [knockouts, len(knockouts), self.production[i], self.biomass[i], fva.lower_bound(self.target), fva.upper_bound(self.target)] except SolveError: self._processed_knockouts.loc[i] = [numpy.nan for _ in self._processed_knockouts.columns]
def test_flux_variability_sequential_remove_cycles(self, core_model): original_objective = core_model.objective fva_solution = flux_variability_analysis(core_model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=SequentialView()) assert REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'] > 666. assert round(abs(fva_solution['upper_bound']['FRD7'] - 0.), 7) == 0 for key in fva_solution.data_frame.index: if REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key] > -666: assert abs( fva_solution['lower_bound'][key] - REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key]) < 0.0001 if REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key] < 666: assert abs( fva_solution['upper_bound'][key] - REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key]) < 0.0001 cycle_reac = Reaction("minus_PGI") # Create fake cycle cycle_reac.lower_bound = -1000 core_model.add_reaction(cycle_reac) cycle_reac.add_metabolites({met: -c for met, c in core_model.reactions.PGI.metabolites.items()}) fva_solution = flux_variability_analysis(core_model, remove_cycles=False, reactions=["PGI"]) assert fva_solution.data_frame.loc["PGI", "upper_bound"] == 1000 fva_solution = flux_variability_analysis(core_model, remove_cycles=True, reactions=["PGI"]) assert fva_solution.data_frame.loc["PGI", "upper_bound"] < 666 assert original_objective == core_model.objective
def test_flux_variability_sequential_remove_cycles(self): fva_solution = flux_variability_analysis( self.model, fraction_of_optimum=0.999999419892, remove_cycles=True, view=SequentialView()) self.assertGreater( REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound']['FRD7'], 1000.) self.assertAlmostEqual(fva_solution['upper_bound']['FRD7'], 0.) for key in fva_solution.data_frame.index: if abs(REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'] [key]) < 1000: self.assertAlmostEqual( fva_solution['lower_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['lower_bound'][key], delta=0.0001) if abs(REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'] [key]) < 1000: self.assertAlmostEqual( fva_solution['upper_bound'][key], REFERENCE_FVA_SOLUTION_ECOLI_CORE['upper_bound'][key], delta=0.0001)
def run(self, surface_only=True, improvements_only=True, progress=True, view=None, fraction_of_optimum=1.0): """Run the differential flux variability analysis. Parameters ---------- surface_only : bool, optional If only the surface of the n-dimensional production envelope should be scanned (defaults to True). improvements_only : bool, optional If only grid points should should be scanned that constitute and improvement in production over the reference state (defaults to True). progress : bool, optional If a progress bar should be shown. view : SequentialView or MultiprocessingView or ipython.cluster.DirectView, optional A parallelization view (defaults to SequentialView). fraction_of_optimum : float, optional A value between zero and one that determines the width of the flux ranges of the reference solution. The lower the value, the larger the ranges. Returns ------- pandas.Panel A pandas Panel containing a results DataFrame for every grid point scanned. """ # Calculate the reference state. self.reference_flux_dist = pfba( self.reference_model, fraction_of_optimum=fraction_of_optimum) self.reference_flux_ranges = flux_variability_analysis( self.reference_model, reactions=self.included_reactions, view=view, remove_cycles=False, fraction_of_optimum=fraction_of_optimum).data_frame self.reference_flux_ranges[ self.reference_flux_ranges.abs() < non_zero_flux_threshold] = 0.0 reference_intervals = self.reference_flux_ranges.loc[ self.included_reactions, ['lower_bound', 'upper_bound']].values if self.normalize_ranges_by is not None: logger.debug( self.reference_flux_ranges.loc[self.normalize_ranges_by, ]) # The most obvious flux to normalize by is the biomass reaction # flux. This is probably always greater than zero. Just in case # the model is defined differently or some other normalizing # reaction is chosen, we use the absolute value. norm = abs(self.reference_flux_ranges.at[self.normalize_ranges_by, "lower_bound"]) if norm > non_zero_flux_threshold: normalized_reference_intervals = reference_intervals / norm else: raise ValueError( "The reaction that you have chosen for normalization '{}' " "has zero flux in the reference state. Please choose another " "one.".format(self.normalize_ranges_by)) with TimeMachine() as tm: # Make sure that the design_space_model is initialized to its original state later for variable in self.variables: reaction = self.design_space_model.reactions.get_by_id( variable) tm(do=int, undo=partial(setattr, reaction, 'lower_bound', reaction.lower_bound)) tm(do=int, undo=partial(setattr, reaction, 'upper_bound', reaction.upper_bound)) target_reaction = self.design_space_model.reactions.get_by_id( self.objective) tm(do=int, undo=partial(setattr, target_reaction, 'lower_bound', target_reaction.lower_bound)) tm(do=int, undo=partial(setattr, target_reaction, 'upper_bound', target_reaction.upper_bound)) if view is None: view = config.default_view else: view = view self._init_search_grid(surface_only=surface_only, improvements_only=improvements_only) func_obj = _DifferentialFvaEvaluator(self.design_space_model, self.variables, self.objective, self.included_reactions) if progress: progress = ProgressBar(len(self.grid)) results = list( progress(view.imap(func_obj, self.grid.iterrows()))) else: results = list(view.map(func_obj, self.grid.iterrows())) solutions = dict((tuple(point.iteritems()), fva_result) for (point, fva_result) in results) for sol in solutions.values(): sol[sol.abs() < non_zero_flux_threshold] = 0.0 intervals = sol.loc[self.included_reactions, ['lower_bound', 'upper_bound']].values gaps = [ self._interval_gap(interval1, interval2) for interval1, interval2 in zip(reference_intervals, intervals) ] sol['gaps'] = gaps if self.normalize_ranges_by is not None: # See comment above regarding normalization. normalizer = abs(sol.lower_bound[self.normalize_ranges_by]) if normalizer > non_zero_flux_threshold: normalized_intervals = sol.loc[ self.included_reactions, ['lower_bound', 'upper_bound']].values / normalizer sol['normalized_gaps'] = [ self._interval_gap(interval1, interval2) for interval1, interval2 in zip( normalized_reference_intervals, normalized_intervals) ] else: sol['normalized_gaps'] = numpy.nan else: sol['normalized_gaps'] = gaps # Determine where the reference flux range overlaps with zero. zero_overlap_mask = numpy.asarray([ self._interval_overlap(interval1, (0, 0)) > 0 for interval1 in reference_intervals ], dtype=bool) collection = list() for key, df in solutions.items(): df['biomass'] = key[0][1] df['production'] = key[1][1] df['KO'] = False df['flux_reversal'] = False df['suddenly_essential'] = False df['free_flux'] = False df.loc[(df.lower_bound == 0) & (df.upper_bound == 0) & (~zero_overlap_mask), 'KO'] = True df.loc[((self.reference_flux_ranges.upper_bound < 0) & (df.lower_bound > 0) | ((self.reference_flux_ranges.lower_bound > 0) & (df.upper_bound < 0))), 'flux_reversal'] = True df.loc[(zero_overlap_mask & (df.lower_bound > 0)) | (zero_overlap_mask & (df.upper_bound < 0)), 'suddenly_essential'] = True is_reversible = numpy.asarray([ self.design_space_model.reactions.get_by_id(i).reversibility for i in df.index ], dtype=bool) not_reversible = ~is_reversible df.loc[((df.lower_bound == -1000) & (df.upper_bound == 1000) & is_reversible) | ((df.lower_bound == 0) & (df.upper_bound == 1000) & not_reversible) | ((df.lower_bound == -1000) & (df.upper_bound == 0) & not_reversible), 'free_flux'] = True df['reaction'] = df.index df['excluded'] = df['reaction'].isin(self.exclude) collection.append(df) # multi_index = [(key[0][1], key[1][1]) for key in solutions] # solutions_multi_index = pandas.concat(list(solutions.values()), # axis=0, keys=multi_index)# # solutions_multi_index.index.set_names(['biomass', 'production', # 'reaction'], inplace=True) total = pandas.concat(collection, ignore_index=True, copy=False) total.sort_values(['biomass', 'production', 'reaction'], inplace=True) total.index = total['reaction'] return DifferentialFVAResult(total, self.envelope, self.reference_flux_ranges)
def run(self, surface_only=True, improvements_only=True, progress=True, view=None): """Run the differential flux variability analysis. Parameters ---------- surface_only : bool, optional If only the surface of the n-dimensional production envelope should be scanned (defaults to True). improvements_only : bool, optional If only grid points should should be scanned that constitute and improvement in production over the reference state (defaults to True). progress : bool, optional If a progress bar should be shown. view : SequentialView or MultiprocessingView or ipython.cluster.DirectView, optional A parallelization view (defaults to SequentialView). Returns ------- pandas.Panel A pandas Panel containing a results DataFrame for every grid point scanned. """ with TimeMachine() as tm: # Make sure that the design_space_model is initialized to its original state later for variable in self.variables: reaction = self.design_space_model.reactions.get_by_id(variable) tm(do=int, undo=partial(setattr, reaction, 'lower_bound', reaction.lower_bound)) tm(do=int, undo=partial(setattr, reaction, 'upper_bound', reaction.upper_bound)) target_reaction = self.design_space_model.reactions.get_by_id(self.objective) tm(do=int, undo=partial(setattr, target_reaction, 'lower_bound', target_reaction.lower_bound)) tm(do=int, undo=partial(setattr, target_reaction, 'upper_bound', target_reaction.upper_bound)) if view is None: view = config.default_view else: view = view included_reactions = [reaction.id for reaction in self.reference_model.reactions if reaction.id not in self.exclude] + self.variables + [self.objective] self.reference_flux_dist = pfba(self.reference_model, fraction_of_optimum=0.99) self.reference_flux_ranges = flux_variability_analysis(self.reference_model, reactions=included_reactions, view=view, remove_cycles=False, fraction_of_optimum=0.75).data_frame self._init_search_grid(surface_only=surface_only, improvements_only=improvements_only) func_obj = _DifferentialFvaEvaluator(self.design_space_model, self.variables, self.objective, included_reactions) if progress: progress = ProgressBar(len(self.grid)) results = list(progress(view.imap(func_obj, self.grid.iterrows()))) else: results = list(view.map(func_obj, self.grid.iterrows())) solutions = dict((tuple(point.iteritems()), fva_result) for (point, fva_result) in results) reference_intervals = self.reference_flux_ranges[['lower_bound', 'upper_bound']].values for sol in six.itervalues(solutions): intervals = sol[['lower_bound', 'upper_bound']].values gaps = [self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, intervals)] sol['gaps'] = gaps if self.normalize_ranges_by is not None: normalizer = sol.lower_bound[self.normalize_ranges_by] if normalizer > non_zero_flux_threshold: normalized_intervals = sol[['lower_bound', 'upper_bound']].values / normalizer sol['normalized_gaps'] = [self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, normalized_intervals)] else: sol['normalized_gaps'] = [numpy.nan] * len(sol.lower_bound) else: sol['normalized_gaps'] = gaps ref_upper_bound = self.reference_flux_ranges.upper_bound.apply( lambda v: 0 if abs(v) < non_zero_flux_threshold else v) ref_lower_bound = self.reference_flux_ranges.lower_bound.apply( lambda v: 0 if abs(v) < non_zero_flux_threshold else v) collection = list() for key, df in six.iteritems(solutions): df['biomass'] = key[0][1] df['production'] = key[1][1] df['KO'] = False df['flux_reversal'] = False df['suddenly_essential'] = False df['free_flux'] = False df.loc[ (df.lower_bound == 0) & ( df.upper_bound == 0) & ( ref_upper_bound != 0) & ( ref_lower_bound != 0), 'KO' ] = True df.loc[ ((ref_upper_bound < 0) & (df.lower_bound > 0) | ( (ref_lower_bound > 0) & (df.upper_bound < 0))), 'flux_reversal' ] = True df.loc[ ((df.lower_bound <= 0) & (df.lower_bound > 0)) | ( (ref_lower_bound >= 0) & (df.upper_bound <= 0)), 'suddenly_essential' ] = True is_reversible = numpy.asarray([ self.design_space_model.reactions.get_by_id(i).reversibility for i in df.index], dtype=bool) not_reversible = numpy.logical_not(is_reversible) df.loc[ ((df.lower_bound == -1000) & (df.upper_bound == 1000) & is_reversible) | ( (df.lower_bound == 0) & (df.upper_bound == 1000) & not_reversible) | ( (df.lower_bound == -1000) & (df.upper_bound == 0) & not_reversible), 'free_flux' ] = True df['reaction'] = df.index df['excluded'] = df['reaction'].isin(self.exclude) collection.append(df) # multi_index = [(key[0][1], key[1][1]) for key in solutions] # solutions_multi_index = pandas.concat(list(solutions.values()), # axis=0, keys=multi_index)# # solutions_multi_index.index.set_names(['biomass', 'production', # 'reaction'], inplace=True) total = pandas.concat(collection, ignore_index=True, copy=False) total.sort_values(['biomass', 'production', 'reaction'], inplace=True) total.index = total['reaction'] return DifferentialFVAResult(total, self.envelope, self.reference_flux_ranges, self.reference_flux_dist)
def run(self, surface_only=True, improvements_only=True, view=None): """Run the differential flux variability analysis. Parameters ---------- surface_only : bool, optional If only the surface of the n-dimensional production envelope should be scanned (defaults to True). improvements_only : bool, optional If only grid points should should be scanned that constitute and improvement in production over the reference state (defaults to True). view : SequentialView or MultiprocessingView or ipython.cluster.DirectView, optional A parallelization view (defaults to SequentialView). Returns ------- pandas.Panel A pandas Panel containing a results DataFrame for every grid point scanned. """ with TimeMachine() as tm: # Make sure that the design_space_model is initialized to its original state later for variable in self.variables: reaction = self.design_space_model.reactions.get_by_id( variable) tm(do=int, undo=partial(setattr, reaction, 'lower_bound', reaction.lower_bound)) tm(do=int, undo=partial(setattr, reaction, 'upper_bound', reaction.upper_bound)) target_reaction = self.design_space_model.reactions.get_by_id( self.objective) tm(do=int, undo=partial(setattr, target_reaction, 'lower_bound', target_reaction.lower_bound)) tm(do=int, undo=partial(setattr, target_reaction, 'upper_bound', target_reaction.upper_bound)) if view is None: view = config.default_view else: view = view included_reactions = [ reaction.id for reaction in self.reference_model.reactions if reaction.id not in self.exclude ] + self.variables + [self.objective] self.reference_flux_dist = pfba(self.reference_model, fraction_of_optimum=0.99) self.reference_flux_ranges = flux_variability_analysis( self.reference_model, reactions=included_reactions, view=view, remove_cycles=False, fraction_of_optimum=0.75).data_frame self._init_search_grid(surface_only=surface_only, improvements_only=improvements_only) progress = ProgressBar(len(self.grid)) func_obj = _DifferentialFvaEvaluator(self.design_space_model, self.variables, self.objective, included_reactions) results = list(progress(view.imap(func_obj, self.grid.iterrows()))) solutions = dict((tuple(point.iteritems()), fva_result) for (point, fva_result) in results) reference_intervals = self.reference_flux_ranges[[ 'lower_bound', 'upper_bound' ]].values for sol in six.itervalues(solutions): intervals = sol[['lower_bound', 'upper_bound']].values gaps = [ self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, intervals) ] sol['gaps'] = gaps if self.normalize_ranges_by is not None: normalizer = sol.lower_bound[self.normalize_ranges_by] normalized_intervals = sol[['lower_bound', 'upper_bound' ]].values / normalizer normalized_gaps = [ self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, normalized_intervals) ] sol['normalized_gaps'] = normalized_gaps else: sol['normalized_gaps'] = gaps ref_upper_bound = self.reference_flux_ranges.upper_bound.apply( lambda v: 0 if abs(v) < non_zero_flux_threshold else v) ref_lower_bound = self.reference_flux_ranges.lower_bound.apply( lambda v: 0 if abs(v) < non_zero_flux_threshold else v) for df in six.itervalues(solutions): df['KO'] = False df['flux_reversal'] = False df['suddenly_essential'] = False df['free_flux'] = False ko_selection = df[(df.lower_bound == 0) & (df.upper_bound == 0) & (ref_upper_bound != 0) & (ref_lower_bound != 0)] flux_reversal_selection = df[((ref_upper_bound < 0) & (df.lower_bound > 0) | ((ref_lower_bound > 0) & (df.upper_bound < 0)))] suddenly_essential_selection = df[((df.lower_bound <= 0) & (df.lower_bound > 0)) | ((ref_lower_bound >= 0) & (df.upper_bound <= 0))] is_reversible = [ self.design_space_model.reactions.get_by_id(i).reversibility for i in df.index ] not_reversible = [not v for v in is_reversible] free_flux_selection = df[((df.lower_bound == -1000) & (df.upper_bound == 1000) & is_reversible) | ((df.lower_bound == 0) & (df.upper_bound == 1000) & not_reversible) | ((df.lower_bound == -1000) & (df.upper_bound == 0) & not_reversible)] df.loc[suddenly_essential_selection.index, 'suddenly_essential'] = True df.loc[ko_selection.index, 'KO'] = True df.loc[flux_reversal_selection.index, 'flux_reversal'] = True df.loc[free_flux_selection.index, 'free_flux'] = True df['excluded'] = [index in self.exclude for index in df.index] return DifferentialFVAResult(pandas.Panel(solutions), self.envelope, self.reference_flux_ranges, self.reference_flux_dist)
def run(self, surface_only=True, improvements_only=True, progress=True, view=None): """Run the differential flux variability analysis. Parameters ---------- surface_only : bool, optional If only the surface of the n-dimensional production envelope should be scanned (defaults to True). improvements_only : bool, optional If only grid points should should be scanned that constitute and improvement in production over the reference state (defaults to True). progress : bool, optional If a progress bar should be shown. view : SequentialView or MultiprocessingView or ipython.cluster.DirectView, optional A parallelization view (defaults to SequentialView). Returns ------- pandas.Panel A pandas Panel containing a results DataFrame for every grid point scanned. """ with TimeMachine() as tm: # Make sure that the design_space_model is initialized to its original state later for variable in self.variables: reaction = self.design_space_model.reactions.get_by_id( variable) tm(do=int, undo=partial(setattr, reaction, 'lower_bound', reaction.lower_bound)) tm(do=int, undo=partial(setattr, reaction, 'upper_bound', reaction.upper_bound)) target_reaction = self.design_space_model.reactions.get_by_id( self.objective) tm(do=int, undo=partial(setattr, target_reaction, 'lower_bound', target_reaction.lower_bound)) tm(do=int, undo=partial(setattr, target_reaction, 'upper_bound', target_reaction.upper_bound)) if view is None: view = config.default_view else: view = view included_reactions = [ reaction.id for reaction in self.reference_model.reactions if reaction.id not in self.exclude ] + self.variables + [self.objective] self.reference_flux_dist = pfba(self.reference_model, fraction_of_optimum=0.99) self.reference_flux_ranges = flux_variability_analysis( self.reference_model, reactions=included_reactions, view=view, remove_cycles=False, fraction_of_optimum=0.75).data_frame self._init_search_grid(surface_only=surface_only, improvements_only=improvements_only) func_obj = _DifferentialFvaEvaluator(self.design_space_model, self.variables, self.objective, included_reactions) if progress: progress = ProgressBar(len(self.grid)) results = list( progress(view.imap(func_obj, self.grid.iterrows()))) else: results = list(view.map(func_obj, self.grid.iterrows())) solutions = dict((tuple(point.iteritems()), fva_result) for (point, fva_result) in results) reference_intervals = self.reference_flux_ranges[[ 'lower_bound', 'upper_bound' ]].values for sol in six.itervalues(solutions): intervals = sol[['lower_bound', 'upper_bound']].values gaps = [ self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, intervals) ] sol['gaps'] = gaps if self.normalize_ranges_by is not None: normalizer = sol.lower_bound[self.normalize_ranges_by] if normalizer > non_zero_flux_threshold: normalized_intervals = sol[['lower_bound', 'upper_bound' ]].values / normalizer sol['normalized_gaps'] = [ self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip( reference_intervals, normalized_intervals) ] else: sol['normalized_gaps'] = [numpy.nan] * len(sol.lower_bound) else: sol['normalized_gaps'] = gaps ref_upper_bound = self.reference_flux_ranges.upper_bound.apply( lambda v: 0 if abs(v) < non_zero_flux_threshold else v) ref_lower_bound = self.reference_flux_ranges.lower_bound.apply( lambda v: 0 if abs(v) < non_zero_flux_threshold else v) collection = list() for key, df in six.iteritems(solutions): df['biomass'] = key[0][1] df['production'] = key[1][1] df['KO'] = False df['flux_reversal'] = False df['suddenly_essential'] = False df['free_flux'] = False df.loc[(df.lower_bound == 0) & (df.upper_bound == 0) & (ref_upper_bound != 0) & (ref_lower_bound != 0), 'KO'] = True df.loc[((ref_upper_bound < 0) & (df.lower_bound > 0) | ((ref_lower_bound > 0) & (df.upper_bound < 0))), 'flux_reversal'] = True df.loc[((df.lower_bound <= 0) & (df.lower_bound > 0)) | ((ref_lower_bound >= 0) & (df.upper_bound <= 0)), 'suddenly_essential'] = True is_reversible = numpy.asarray([ self.design_space_model.reactions.get_by_id(i).reversibility for i in df.index ], dtype=bool) not_reversible = numpy.logical_not(is_reversible) df.loc[((df.lower_bound == -1000) & (df.upper_bound == 1000) & is_reversible) | ((df.lower_bound == 0) & (df.upper_bound == 1000) & not_reversible) | ((df.lower_bound == -1000) & (df.upper_bound == 0) & not_reversible), 'free_flux'] = True df['reaction'] = df.index df['excluded'] = df['reaction'].isin(self.exclude) collection.append(df) # multi_index = [(key[0][1], key[1][1]) for key in solutions] # solutions_multi_index = pandas.concat(list(solutions.values()), # axis=0, keys=multi_index)# # solutions_multi_index.index.set_names(['biomass', 'production', # 'reaction'], inplace=True) total = pandas.concat(collection, ignore_index=True, copy=False) total.sort_values(['biomass', 'production', 'reaction'], inplace=True) total.index = total['reaction'] return DifferentialFVAResult(total, self.envelope, self.reference_flux_ranges, self.reference_flux_dist)
def run(self, surface_only=True, improvements_only=True, view=None): """Run the differential flux variability analysis. Parameters ---------- surface_only : bool, optional If only the surface of the n-dimensional production envelope should be scanned (defaults to True). improvements_only : bool, optional If only grid points should should be scanned that constitute and improvement in production over the reference state (defaults to True). view : SequentialView or MultiprocessingView or ipython.cluster.DirectView, optional A parallelization view (defaults to SequentialView). Returns ------- pandas.Panel A pandas Panel containing a results DataFrame for every grid point scanned. """ with TimeMachine() as tm: # Make sure that the design_space_model is initialized to its original state later for variable in self.variables: reaction = self.design_space_model.reactions.get_by_id(variable) tm(do=int, undo=partial(setattr, reaction, 'lower_bound', reaction.lower_bound)) tm(do=int, undo=partial(setattr, reaction, 'upper_bound', reaction.upper_bound)) target_reaction = self.design_space_model.reactions.get_by_id(self.objective) tm(do=int, undo=partial(setattr, target_reaction, 'lower_bound', target_reaction.lower_bound)) tm(do=int, undo=partial(setattr, target_reaction, 'upper_bound', target_reaction.upper_bound)) if view is None: view = config.default_view else: view = view included_reactions = [reaction.id for reaction in self.reference_model.reactions if reaction.id not in self.exclude] # FIXME: reference flux ranges should be for a fraction (say 0.75) of the original objective self.reference_flux_ranges = flux_variability_analysis(self.reference_model, reactions=included_reactions, view=view, remove_cycles=False).data_frame self._init_search_grid(surface_only=surface_only, improvements_only=improvements_only) progress = ProgressBar(len(self.grid)) func_obj = _DifferentialFvaEvaluator(self.design_space_model, self.variables, self.objective, included_reactions) results = list(progress(view.imap(func_obj, self.grid.iterrows()))) solutions = dict((tuple(point.iteritems()), fva_result.data_frame) for (point, fva_result) in results) reference_intervals = self.reference_flux_ranges[['lower_bound', 'upper_bound']].values for sol in six.itervalues(solutions): intervals = sol[['lower_bound', 'upper_bound']].values gaps = [self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, intervals)] sol['gaps'] = gaps if self.normalize_ranges_by is not None: normalized_intervals = sol[['lower_bound', 'upper_bound']].values / sol.lower_bound[ self.normalize_ranges_by] normalized_gaps = [self._interval_gap(interval1, interval2) for interval1, interval2 in my_zip(reference_intervals, normalized_intervals)] sol['normalized_gaps'] = normalized_gaps else: sol['normalized_gaps'] = gaps chopped_ref_lower_bounds = self.reference_flux_ranges.lower_bound.apply(lambda x: 0 if abs(x) < non_zero_flux_threshold else x) chopped_ref_upper_bounds = self.reference_flux_ranges.upper_bound.apply(lambda x: 0 if abs(x) < non_zero_flux_threshold else x) for df in six.itervalues(solutions): df_chopped = df.applymap(lambda x: 0 if abs(x) < non_zero_flux_threshold else x) ko_selection = df[(df_chopped.lower_bound == 0) & (df_chopped.upper_bound == 0) & (chopped_ref_lower_bounds != 0) & chopped_ref_upper_bounds != 0] df['KO'] = False df.loc[ko_selection.index, 'KO'] = True for df in six.itervalues(solutions): df_chopped = df.applymap(lambda x: 0 if abs(x) < non_zero_flux_threshold else x) flux_reversal_selection = df[((chopped_ref_upper_bounds < 0) & (df_chopped.lower_bound > 0) | ((chopped_ref_lower_bounds > 0) & (df_chopped.upper_bound < 0)))] df['flux_reversal'] = False df.loc[flux_reversal_selection.index, 'flux_reversal'] = True for df in six.itervalues(solutions): df_chopped = df.applymap(lambda x: 0 if abs(x) < non_zero_flux_threshold else x) suddenly_essential_selection = df[((df_chopped.lower_bound <= 0) & (df_chopped.lower_bound > 0)) | ( (chopped_ref_upper_bounds >= 0) & (df_chopped.upper_bound <= 0))] df['suddenly_essential'] = False df.loc[suddenly_essential_selection.index, 'suddenly_essential'] = True if self.objective is None: objective = self.reference_model.objective else: objective = self.objective if isinstance(objective, Reaction): if hasattr(self.objective, 'nice_id'): nice_objective_id = objective.nice_id objective = objective.id else: objective = objective.id nice_objective_id = objective else: objective = str(self.objective) nice_objective_id = str(objective) return DifferentialFVAResult(pandas.Panel(solutions), self.envelope, self.reference_flux_ranges, self.variables, objective, nice_objective_id=nice_objective_id, nice_variable_ids=self.variables)