def test_incompatible_targets(self): ko_target = ReactionKnockoutTarget("a") ki_target = ReactionKnockinTarget("a", None) with pytest.raises(IncompatibleTargets): EnsembleTarget("a", [ko_target, ki_target]) with pytest.raises(IncompatibleTargets): EnsembleTarget("a", [ki_target, ko_target]) ko_target = ReactionKnockoutTarget("b") swap_target = ReactionCofactorSwapTarget("b", [("nad_c", "nadh_c"), ("nadp_c", "nadph_c")]) with pytest.raises(IncompatibleTargets): EnsembleTarget("b", [ko_target, swap_target]) with pytest.raises(IncompatibleTargets): EnsembleTarget("b", [swap_target, ko_target]) modulation_target = ReactionModulationTarget("c", 0, 0) ki_target = ReactionKnockinTarget("c", None) with pytest.raises(IncompatibleTargets): EnsembleTarget("c", [modulation_target, ki_target]) with pytest.raises(IncompatibleTargets): EnsembleTarget("c", [ki_target, modulation_target])
def test_add_strain_design(self): t1 = ReactionKnockoutTarget('PGI') t2 = ReactionKnockoutTarget('GAPD') t3 = ReactionKnockinTarget("CAD", self.cad_reaction) strain_design1 = StrainDesign([t1, t2, t3]) t4 = ReactionModulationTarget("PGI", 5, 1) strain_design2 = StrainDesign([t4]) self.assertRaises(IncompatibleTargets, strain_design1.__add__, strain_design2) self.assertRaises(IncompatibleTargets, strain_design2.__add__, strain_design1) self.assertRaises(IncompatibleTargets, strain_design1.__iadd__, strain_design2) self.assertRaises(IncompatibleTargets, strain_design2.__iadd__, strain_design1) t5 = ReactionModulationTarget("RPI", 2, 0) strain_design3 = StrainDesign([t5]) strain_design4 = strain_design3 + strain_design1 self.assertIn(t1, strain_design4) self.assertIn(t2, strain_design4) self.assertIn(t3, strain_design4) self.assertNotIn(t4, strain_design4) self.assertIn(t5, strain_design4) strain_design3 += strain_design1 self.assertIn(t1, strain_design3) self.assertIn(t2, strain_design3) self.assertIn(t3, strain_design3) self.assertNotIn(t4, strain_design3) self.assertIn(t5, strain_design3)
def test_hashable(self): knockout_target1 = ReactionKnockoutTarget("ACALD") knockout_target2 = ReactionKnockoutTarget("ACALD") assert knockout_target1 == knockout_target2 assert hash(knockout_target1) == hash(knockout_target2) assert len({knockout_target1, knockout_target2}) == 1
def test_reaction_knockout_target(self, model): knockout_target = ReactionKnockoutTarget("ACALD") with model: knockout_target.apply(model) assert model.reactions.ACALD.lower_bound == 0 assert model.reactions.ACALD.upper_bound == 0 assert model.reactions.ACALD.lower_bound == -1000 assert model.reactions.ACALD.upper_bound == 1000
def test_reaction_knockout_target(self, model): knockout_target = ReactionKnockoutTarget("ACALD") with TimeMachine() as tm: knockout_target.apply(model, time_machine=tm) assert model.reactions.ACALD.lower_bound == 0 assert model.reactions.ACALD.upper_bound == 0 assert model.reactions.ACALD.lower_bound == -1000 assert model.reactions.ACALD.upper_bound == 1000
def test_design_to_gnomic(self, cad_reaction): from gnomic import Genotype t1 = ReactionKnockoutTarget('PGI') t2 = ReactionKnockoutTarget('GAPD') t3 = ReactionKnockinTarget("CAD", cad_reaction) strain_design1 = StrainDesign([t1, t2, t3]) sd_gnomic = strain_design1.to_gnomic() assert isinstance(sd_gnomic, Genotype) assert len(sd_gnomic.added_features) == 1 assert len(sd_gnomic.removed_features) == 2
def test_design_to_gnomic(self): from gnomic import Genotype t1 = ReactionKnockoutTarget('PGI') t2 = ReactionKnockoutTarget('GAPD') t3 = ReactionKnockinTarget("CAD", self.cad_reaction) strain_design1 = StrainDesign([t1, t2, t3]) sd_gnomic = strain_design1.to_gnomic() self.assertIsInstance(sd_gnomic, Genotype) self.assertEqual(len(sd_gnomic.added_features), 1) self.assertEqual(len(sd_gnomic.removed_features), 2)
def _generate_designs(knockouts): designs = [] for knockout_design in knockouts: designs.append( StrainDesign( [ReactionKnockoutTarget(ko for ko in knockout_design)])) return designs
def test_create_strain_design(self, cad_reaction): t1 = ReactionKnockoutTarget('PGI') t2 = ReactionKnockoutTarget('GAPD') t3 = ReactionKnockinTarget("CAD", cad_reaction) strain_design = StrainDesign([t1, t2, t3]) assert len(strain_design) == 3 strain_design2 = StrainDesign([t1, t2, t3]) strain_design3 = StrainDesign([t2, t1, t3]) assert strain_design == strain_design2 assert strain_design == strain_design3 assert strain_design3 == strain_design2 assert t1 in strain_design assert t2 in strain_design assert t3 in strain_design
def test_create_strain_design(self): t1 = ReactionKnockoutTarget('PGI') t2 = ReactionKnockoutTarget('GAPD') t3 = ReactionKnockinTarget("CAD", self.cad_reaction) strain_design = StrainDesign([t1, t2, t3]) self.assertEqual(len(strain_design), 3) strain_design2 = StrainDesign([t1, t2, t3]) strain_design3 = StrainDesign([t2, t1, t3]) self.assertEqual(strain_design, strain_design2) self.assertEqual(strain_design, strain_design3) self.assertEqual(strain_design3, strain_design2) self.assertIn(t1, strain_design) self.assertIn(t2, strain_design) self.assertIn(t3, strain_design)
def _generate_designs(reference, enforced_levels, reaction_results): for i, level in enumerate(enforced_levels): targets = [] for reaction, value in six.iteritems(reaction_results): if abs(reference[reaction.id]) > 0: if value[i] == 0: targets.append(ReactionKnockoutTarget(reaction.id)) elif value[i] > reference[reaction.id]: targets.append(ReactionModulationTarget(reaction.id, value[i], reference[reaction.id])) yield StrainDesign(targets)
def test_add_strain_design(self, cad_reaction): t1 = ReactionKnockoutTarget('PGI') t2 = ReactionKnockoutTarget('GAPD') t3 = ReactionKnockinTarget("CAD", cad_reaction) strain_design1 = StrainDesign([t1, t2, t3]) t4 = ReactionModulationTarget("PGI", 5, 1) strain_design2 = StrainDesign([t4]) with pytest.raises(IncompatibleTargets): strain_design1.__add__(strain_design2) with pytest.raises(IncompatibleTargets): strain_design2.__add__(strain_design1) with pytest.raises(IncompatibleTargets): strain_design1.__iadd__(strain_design2) with pytest.raises(IncompatibleTargets): strain_design2.__iadd__(strain_design1) t5 = ReactionModulationTarget("RPI", 2, 0) strain_design3 = StrainDesign([t5]) strain_design4 = strain_design3 + strain_design1 assert t1 in strain_design4 assert t2 in strain_design4 assert t3 in strain_design4 assert t4 not in strain_design4 assert t5 in strain_design4 strain_design3 += strain_design1 assert t1 in strain_design3 assert t2 in strain_design3 assert t3 in strain_design3 assert t4 not in strain_design3 assert t5 in strain_design3
def _generate_designs(cls, solutions, reference_fva, reference_fluxes): """ Generates strain designs for Differential FVA. The conversion method has three scenarios: #### 1. Knockout Creates a ReactionKnockoutTarget. #### 2. Flux reversal If the new flux is negative then it should be at least the upper bound of the interval. Otherwise it should be at least the lower bound of the interval. #### 3. The flux increases or decreases This table illustrates the possible combinations. * Gap is the sign of the normalized gap between the intervals. * Ref is the sign of the closest bound (see _closest_bound). * Bound is the value to use +-------------------+ | Gap | Ref | Bound | +-----+-----+-------+ | - | - | LB | | - | + | UB | | + | - | UB | | + | + | LB | +-----+-----+-------+ Parameters ---------- solutions: pandas.Panel The DifferentialFVA panel with all the solutions. Each DataFrame is a design. reference_fva: pandas.DataFrame The FVA limits for the reference strain. reference_fluxes: The optimal flux distribution for the reference strain. Returns ------- list A list of cameo.core.strain_design.StrainDesign for each DataFrame in solutions. """ designs = [] for _, solution in solutions.groupby(('biomass', 'production')): targets = [] relevant_targets = solution.loc[ (numpy.abs(solution['normalized_gaps']) > non_zero_flux_threshold) & (numpy.logical_not(solution['excluded'])) & (numpy.logical_not(solution['free_flux']))] for rid, relevant_row in relevant_targets.iterrows(): if relevant_row.KO: targets.append(ReactionKnockoutTarget(rid)) elif relevant_row.flux_reversal: if reference_fva['upper_bound'][rid] > 0: targets.append( ReactionInversionTarget( rid, value=float_ceil(relevant_row.upper_bound, ndecimals), reference_value=reference_fluxes[rid])) else: targets.append( ReactionInversionTarget( rid, value=float_floor(relevant_row.lower_bound, ndecimals), reference_value=reference_fluxes[rid])) else: gap_sign = relevant_row.normalized_gaps > 0 ref_interval = reference_fva[[ 'lower_bound', 'upper_bound' ]].loc[rid].values row_interval = (relevant_row.lower_bound, relevant_row.upper_bound) closest_bound, ref_sign = cls._closest_bound( ref_interval, row_interval) if gap_sign ^ ref_sign: value = float_ceil(relevant_row.upper_bound, ndecimals) else: value = float_floor(relevant_row.lower_bound, ndecimals) targets.append( ReactionModulationTarget( rid, value=value, reference_value=reference_fva[closest_bound][rid])) designs.append(StrainDesign(targets)) return designs
def test_invalid_reaction_knockout_target(self, model): knockout_target = ReactionKnockoutTarget("ACALDXYZ") with pytest.raises(KeyError): knockout_target.apply(model)
def _generate_designs(cls, solutions, reference_fva): """ Generates strain designs for Differential FVA. The conversion method has three scenarios: #### 1. Knockout Creates a ReactionKnockoutTarget. #### 2. Flux reversal If the new flux is negative then it should be at least the upper bound of the interval. Otherwise it should be at least the lower bound of the interval. #### 3. The flux increases or decreases This table illustrates the possible combinations. * Gap is the sign of the normalized gap between the intervals. * Ref is the sign of the closest bound (see _closest_bound). * Bound is the value to use +-------------------+ | Gap | Ref | Bound | +-----+-----+-------+ | - | - | LB | | - | + | UB | | + | - | UB | | + | + | LB | +-----+-----+-------+ Parameters ---------- solutions: pandas.Panel The DifferentialFVA panel with all the solutions. Each DataFrame is a design. reference_fva: pandas.DataFrame The FVA limits for the reference strain. Returns ------- list A list of cameo.core.strain_design.StrainDesign for each DataFrame in solutions. """ designs = [] for _, solution in solutions.groupby(['biomass', 'production'], as_index=False, sort=False): targets = [] relevant_targets = solution[ (solution['normalized_gaps'].abs() > non_zero_flux_threshold) & (~solution['excluded']) & (~solution['free_flux'])] # Generate all knock-out targets. for rid in relevant_targets.loc[relevant_targets["KO"], "reaction"]: targets.append(ReactionKnockoutTarget(rid)) # Generate all flux inversion targets. for row in relevant_targets[ relevant_targets["flux_reversal"]].itertuples(): rid = row.Index ref_lower = reference_fva.at[rid, 'lower_bound'] ref_upper = reference_fva.at[rid, 'upper_bound'] if ref_upper > 0: # Production point is negative so closest inversion is # from reference lower bound to production upper bound. targets.append( ReactionInversionTarget(rid, value=row.upper_bound, reference_value=ref_lower)) else: # Production point is positive so closest inversion is # from reference upper bound to production lower bound. targets.append( ReactionInversionTarget(rid, value=row.lower_bound, reference_value=ref_upper)) # Generate all suddenly essential targets where we know the # reference interval lies around zero. for row in relevant_targets[ relevant_targets["suddenly_essential"]].itertuples(): rid = row.Index if row.lower_bound > 0: targets.append( ReactionModulationTarget( rid, value=row.lower_bound, reference_value=reference_fva.at[rid, "upper_bound"])) else: targets.append( ReactionModulationTarget( rid, value=row.upper_bound, reference_value=reference_fva.at[rid, "lower_bound"])) # Generate all other flux modulation targets. for row in relevant_targets[ (~relevant_targets["KO"]) & (~relevant_targets["flux_reversal"]) & (~relevant_targets["suddenly_essential"])].itertuples(): rid = row.Index ref_lower = reference_fva.at[rid, 'lower_bound'] ref_upper = reference_fva.at[rid, 'upper_bound'] if row.normalized_gaps > 0: # For now we ignore reactions that have a positive # normalized gap, indicating that their flux is important # for production, but where the reference flux is higher # than the production flux. if abs(ref_upper) > abs(row.lower_bound): continue targets.append( ReactionModulationTarget( rid, value=row.lower_bound, reference_value=ref_upper, fold_change=row.normalized_gaps)) else: # For now we ignore reactions that have a negative # normalized gap, indicating that their flux needs to # decrease in production, but where the production # interval is larger than the reference interval. if abs(row.upper_bound) > abs(ref_lower): continue targets.append( ReactionModulationTarget( rid, value=row.upper_bound, reference_value=ref_lower, fold_change=row.normalized_gaps)) designs.append(StrainDesign(targets)) return designs