class TestMassConsistencyZeroMass(unittest.TestCase): """Test mass consistency using a model with zero-mass compound""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction( '|A| + |B| => |C|')) self.database.set_reaction('rxn_2', parse_reaction( '|C| + |Z| => |A| + |B|')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_is_consistent_with_zeromass(self): consistent = massconsistency.is_consistent( self.model, solver=self.solver, zeromass={Compound('Z')}) self.assertTrue(consistent) def test_compound_consistency_with_zeromass(self): compounds = dict(massconsistency.check_compound_consistency( self.model, solver=self.solver, zeromass={Compound('Z')})) for c, value in iteritems(compounds): self.assertGreaterEqual(value, 1) def test_reaction_consistency_with_zeromass(self): reactions, _ = massconsistency.check_reaction_consistency( self.model, solver=self.solver, zeromass={Compound('Z')}) reactions = dict(reactions) for r, value in iteritems(reactions): self.assertAlmostEqual(value, 0)
class TestFastcoreTinyBiomassModel(unittest.TestCase): """Test fastcore using a model with tiny values in biomass reaction This model is consistent mathematically since there is a flux solution within the flux bounds. However, the numerical nature of the fastcore algorithm requires an epsilon-parameter indicating the minimum flux that is considered non-zero. For this reason, some models with reactions where tiny stoichiometric values appear can be seen as inconsistent by fastcore. In this particular model, rxn_2 can take a maximum flux of 1000. At the same time rxn_1 will have to take a flux of 1e-4. This is the maximum possible flux for rxn_1 so running fastcore with an epsilon larger than 1e-4 will indicate that the model is not consistent. """ def setUp(self): # TODO use mock model instead of actual model self.database = DictDatabase() self.database.set_reaction("rxn_1", parse_reaction("=> |A|")) self.database.set_reaction("rxn_2", parse_reaction("(0.000001) |A| =>")) self.model = MetabolicModel.load_model(self.database, self.database.reactions) self.solver = cplex.Solver() def test_fastcc_is_consistent(self): self.assertTrue(fastcore.fastcc_is_consistent(self.model, 0.001, solver=self.solver)) def test_fastcore_induced_model(self): core = {"rxn_2"} self.assertEquals(set(fastcore.fastcore(self.model, core, 0.001, solver=self.solver)), {"rxn_1", "rxn_2"}) def test_fastcore_induced_model_high_epsilon(self): core = {"rxn_2"} self.assertEquals(set(fastcore.fastcore(self.model, core, 0.1, solver=self.solver)), {"rxn_1", "rxn_2"})
class TestMassConsistencyZeroMass(unittest.TestCase): """Test mass consistency using a model with zero-mass compound""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('|A| + |B| => |C|')) self.database.set_reaction('rxn_2', parse_reaction('|C| + |Z| => |A| + |B|')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_is_consistent_with_zeromass(self): consistent = massconsistency.is_consistent(self.model, solver=self.solver, zeromass={Compound('Z')}) self.assertTrue(consistent) def test_compound_consistency_with_zeromass(self): compounds = dict( massconsistency.check_compound_consistency( self.model, solver=self.solver, zeromass={Compound('Z')})) for c, value in iteritems(compounds): self.assertGreaterEqual(value, 1) def test_reaction_consistency_with_zeromass(self): reactions, _ = massconsistency.check_reaction_consistency( self.model, solver=self.solver, zeromass={Compound('Z')}) reactions = dict(reactions) for r, value in iteritems(reactions): self.assertAlmostEqual(value, 0)
class TestFluxBalanceThermodynamic(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('ex_A', parse_reaction('|A| <=>')) self.database.set_reaction('ex_D', parse_reaction('|D| <=>')) self.database.set_reaction('rxn_1', parse_reaction('|A| => |B|')) self.database.set_reaction('rxn_2', parse_reaction('|B| <=> |C|')) self.database.set_reaction('rxn_3', parse_reaction('|C| <=> |D|')) self.database.set_reaction('rxn_4', parse_reaction('|D| <=> |E|')) self.database.set_reaction('rxn_5', parse_reaction('|E| => |B|')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) self.model.limits['ex_A'].lower = -10 # Low uptake self.model.limits['ex_D'].lower = 0 # No uptake try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Unable to find an MILP solver for tests') def test_flux_balance_tfba_exchange_d(self): fluxes = dict(fluxanalysis.flux_balance( self.model, 'ex_D', tfba=True, solver=self.solver)) self.assertAlmostEqual(fluxes['ex_A'], -10) self.assertAlmostEqual(fluxes['ex_D'], 10) self.assertAlmostEqual(fluxes['rxn_2'], 10) self.assertAlmostEqual(fluxes['rxn_4'], 0) self.assertAlmostEqual(fluxes['rxn_5'], 0)
class TestFluxBalanceThermodynamic(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('ex_A', parse_reaction('|A| <=>')) self.database.set_reaction('ex_D', parse_reaction('|D| <=>')) self.database.set_reaction('rxn_1', parse_reaction('|A| => |B|')) self.database.set_reaction('rxn_2', parse_reaction('|B| <=> |C|')) self.database.set_reaction('rxn_3', parse_reaction('|C| <=> |D|')) self.database.set_reaction('rxn_4', parse_reaction('|D| <=> |E|')) self.database.set_reaction('rxn_5', parse_reaction('|E| => |B|')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) self.model.limits['ex_A'].lower = -10 # Low uptake self.model.limits['ex_D'].lower = 0 # No uptake self.solver = cplex.Solver() def test_flux_balance_tfba_exchange_d(self): fluxes = dict(fluxanalysis.flux_balance( self.model, 'ex_D', tfba=True, solver=self.solver)) self.assertEquals(fluxes['ex_A'], -10) self.assertEquals(fluxes['ex_D'], 10) self.assertEquals(fluxes['rxn_2'], 10) self.assertEquals(fluxes['rxn_4'], 0) self.assertEquals(fluxes['rxn_5'], 0)
class TestFluxBalanceThermodynamic(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('ex_A', parse_reaction('|A| <=>')) self.database.set_reaction('ex_D', parse_reaction('|D| <=>')) self.database.set_reaction('rxn_1', parse_reaction('|A| => |B|')) self.database.set_reaction('rxn_2', parse_reaction('|B| <=> |C|')) self.database.set_reaction('rxn_3', parse_reaction('|C| <=> |D|')) self.database.set_reaction('rxn_4', parse_reaction('|D| <=> |E|')) self.database.set_reaction('rxn_5', parse_reaction('|E| => |B|')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) self.model.limits['ex_A'].lower = -10 # Low uptake self.model.limits['ex_D'].lower = 0 # No uptake try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Unable to find an MILP solver for tests') def test_flux_balance_tfba_exchange_d(self): fluxes = dict( fluxanalysis.flux_balance(self.model, 'ex_D', tfba=True, solver=self.solver)) self.assertAlmostEqual(fluxes['ex_A'], -10) self.assertAlmostEqual(fluxes['ex_D'], 10) self.assertAlmostEqual(fluxes['rxn_2'], 10) self.assertAlmostEqual(fluxes['rxn_4'], 0) self.assertAlmostEqual(fluxes['rxn_5'], 0)
class TestMassConsistencyZeroMass(unittest.TestCase): """Test mass consistency using a model with zero-mass compound""" def setUp(self): # TODO use mock model instead of actual model self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction( '|A| + |B| => |C|')) self.database.set_reaction('rxn_2', parse_reaction( '|C| + |Z| => |A| + |B|')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) self.solver = cplex.Solver() def test_is_consistent_with_zeromass(self): consistent = massconsistency.is_consistent( self.model, solver=self.solver, zeromass={'Z'}) self.assertTrue(consistent) def test_compound_consistency_with_zeromass(self): compounds = dict(massconsistency.check_compound_consistency( self.model, solver=self.solver, zeromass={'Z'})) self.assertEquals(compounds[Compound('Z')], 0) for c, value in compounds.iteritems(): if c.name != 'Z': self.assertGreaterEqual(value, 1) def test_reaction_consistency_with_zeromass(self): reactions, _ = massconsistency.check_reaction_consistency( self.model, solver=self.solver, zeromass={'Z'}) reactions = dict(reactions) for r, value in reactions.iteritems(): self.assertEqual(value, 0)
def test_load_model_with_reaction_subset(self): database = DictDatabase() database.set_reaction('rxn_1', parse_reaction('|A| => |B|')) database.set_reaction('rxn_2', parse_reaction('|B| => |C|')) database.set_reaction('rxn_3', parse_reaction('|C| => |D|')) model = MetabolicModel.load_model(database, {'rxn_1'}) self.assertEqual(set(model.reactions), {'rxn_1'})
class TestFastcoreTinyBiomassModel(unittest.TestCase): """Test fastcore using a model with tiny values in biomass reaction This model is consistent mathematically since there is a flux solution within the flux bounds. However, the numerical nature of the fastcore algorithm requires an epsilon-parameter indicating the minimum flux that is considered non-zero. For this reason, some models with reactions where tiny stoichiometric values appear can be seen as inconsistent by fastcore. In this particular model, rxn_2 can take a maximum flux of 1000. At the same time rxn_1 will have to take a flux of 1e-3. This is the maximum possible flux for rxn_1 so running fastcore with an epsilon larger than 1e-3 will indicate that the model is not consistent. """ def setUp(self): # TODO use mock model instead of actual model self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> |A|')) self.database.set_reaction('rxn_2', parse_reaction('(0.000001) |A| =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_fastcc_is_consistent(self): self.assertTrue( fastcore.fastcc_is_consistent(self.model, 0.0001, solver=self.solver)) def test_fastcc_is_consistent_high_epsilon(self): self.assertFalse( fastcore.fastcc_is_consistent(self.model, 0.1, solver=self.solver)) def test_fastcore_induced_model(self): core = {'rxn_2'} self.assertEqual( set( fastcore.fastcore(self.model, core, 0.0001, scaling=1e7, solver=self.solver)), {'rxn_1', 'rxn_2'}) def test_fastcore_induced_model_high_epsilon(self): core = {'rxn_2'} self.assertEqual( set( fastcore.fastcore(self.model, core, 0.1, scaling=1e7, solver=self.solver)), {'rxn_1', 'rxn_2'})
class TestLinearMOMA(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_moma_fba(self): p = moma.MOMAProblem(self.model, self.solver) fluxes = p.get_fba_flux('rxn_6') self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_moma_minimal_fba(self): p = moma.MOMAProblem(self.model, self.solver) fluxes = p.get_minimal_fba_flux('rxn_6') self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_3'], 1000) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_linear_moma(self): p = moma.MOMAProblem(self.model, self.solver) with p.constraints(p.get_flux_var('rxn_3') == 0): p.lin_moma({ 'rxn_3': 1000, 'rxn_4': 0, 'rxn_5': 0, }) # The closest solution when these are constrained is for # rxn_6 to take on a flux of zero. self.assertAlmostEqual(p.get_flux('rxn_6'), 0) def test_linear_moma2(self): p = moma.MOMAProblem(self.model, self.solver) with p.constraints(p.get_flux_var('rxn_3') == 0): p.lin_moma2('rxn_6', 1000) self.assertAlmostEqual(p.get_flux('rxn_1'), 500) self.assertAlmostEqual(p.get_flux('rxn_2'), 0) self.assertAlmostEqual(p.get_flux('rxn_3'), 0) self.assertAlmostEqual(p.get_flux('rxn_4'), 1000) self.assertAlmostEqual(p.get_flux('rxn_5'), 1000) self.assertAlmostEqual(p.get_flux('rxn_6'), 1000)
class TestLinearMOMA(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_moma_fba(self): p = moma.MOMAProblem(self.model, self.solver) fluxes = p.get_fba_flux('rxn_6') self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_moma_minimal_fba(self): p = moma.MOMAProblem(self.model, self.solver) fluxes = p.get_minimal_fba_flux('rxn_6') self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_3'], 1000) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_linear_moma(self): p = moma.MOMAProblem(self.model, self.solver) with p.constraints(p.get_flux_var('rxn_3') == 0): p.lin_moma({ 'rxn_3': 1000, 'rxn_4': 0, 'rxn_5': 0, }) # The closest solution when these are constrained is for # rxn_6 to take on a flux of zero. self.assertAlmostEqual(p.get_flux('rxn_6'), 0) def test_linear_moma2(self): p = moma.MOMAProblem(self.model, self.solver) with p.constraints(p.get_flux_var('rxn_3') == 0): p.lin_moma2('rxn_6', 1000) self.assertAlmostEqual(p.get_flux('rxn_1'), 500) self.assertAlmostEqual(p.get_flux('rxn_2'), 0) self.assertAlmostEqual(p.get_flux('rxn_3'), 0) self.assertAlmostEqual(p.get_flux('rxn_4'), 1000) self.assertAlmostEqual(p.get_flux('rxn_5'), 1000) self.assertAlmostEqual(p.get_flux('rxn_6'), 1000)
class TestFastcoreTinyBiomassModel(unittest.TestCase): """Test fastcore using a model with tiny values in biomass reaction This model is consistent mathematically since there is a flux solution within the flux bounds. However, the numerical nature of the fastcore algorithm requires an epsilon-parameter indicating the minimum flux that is considered non-zero. For this reason, some models with reactions where tiny stoichiometric values appear can be seen as inconsistent by fastcore. In this particular model, rxn_2 can take a maximum flux of 1000. At the same time rxn_1 will have to take a flux of 1e-3. This is the maximum possible flux for rxn_1 so running fastcore with an epsilon larger than 1e-3 will indicate that the model is not consistent. """ def setUp(self): # TODO use mock model instead of actual model self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> |A|')) self.database.set_reaction('rxn_2', parse_reaction('(0.000001) |A| =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') # Skip these tests with GLPK because of issue #61. if self.solver.properties['name'] == 'glpk': self.skipTest('Test has known issue with GLPK') def test_fastcc_is_consistent(self): self.assertTrue(fastcore.fastcc_is_consistent( self.model, 0.0001, solver=self.solver)) def test_fastcc_is_consistent_high_epsilon(self): self.assertFalse(fastcore.fastcc_is_consistent( self.model, 0.1, solver=self.solver)) def test_fastcore_induced_model(self): core = {'rxn_2'} self.assertEqual( set(fastcore.fastcore( self.model, core, 0.0001, scaling=1e7, solver=self.solver)), {'rxn_1', 'rxn_2'}) def test_fastcore_induced_model_high_epsilon(self): core = {'rxn_2'} self.assertEqual( set(fastcore.fastcore( self.model, core, 0.1, scaling=1e7, solver=self.solver)), {'rxn_1', 'rxn_2'})
class TestRandomSparse(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('A[e] => B[e]')) self._database.set_reaction('rxn_2', parse_reaction('B[e] => C[e]')) self._database.set_reaction('rxn_3', parse_reaction('B[e] => D[e]')) self._database.set_reaction('rxn_4', parse_reaction('C[e] => E[e]')) self._database.set_reaction('rxn_5', parse_reaction('D[e] => E[e]')) self._database.set_reaction('rxn_6', parse_reaction('E[e] =>')) self._database.set_reaction('ex_A', parse_reaction('A[e] <=>')) self._mm = MetabolicModel.load_model( self._database, self._database.reactions) self._assoc = { 'rxn_1': boolean.Expression('gene_1'), 'rxn_2': boolean.Expression('gene_2 or gene_3'), 'rxn_5': boolean.Expression('gene_3 and gene_4') } self._obj_reaction = 'rxn_6' try: self._solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') self._prob = fluxanalysis.FluxBalanceProblem(self._mm, self._solver) def test_random_sparse_reaction_strategy(self): expected = [ ({'rxn_1', 'rxn_6', 'ex_A', 'rxn_2', 'rxn_4'}, {'rxn_3', 'rxn_5'}), ({'rxn_1', 'rxn_6', 'ex_A', 'rxn_3', 'rxn_5'}, {'rxn_2', 'rxn_4'}) ] strategy = randomsparse.ReactionDeletionStrategy(self._mm) essential, deleted = randomsparse.random_sparse( strategy, self._prob, self._obj_reaction, flux_threshold=100) self.assertTrue((essential, deleted) in expected) def test_random_sparse_gene_strategy(self): expected = [ ({'gene_1', 'gene_2'}, {'gene_3', 'gene_4'}), ({'gene_1', 'gene_3'}, {'gene_2', 'gene_4'}) ] strategy = randomsparse.GeneDeletionStrategy( self._mm, self._assoc) essential, deleted = randomsparse.random_sparse( strategy, self._prob, self._obj_reaction, flux_threshold=100) self.assertTrue((essential, deleted) in expected)
class TestMetabolicModelFlipableView(unittest.TestCase): def setUp(self): # TODO use mock database instead of actual database self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) model = MetabolicModel.load_model(self.database, self.database.reactions) self.model = FlipableModelView(model) def test_flipable_model_view_matrix_get_item_after_flip(self): self.model.flip({'rxn_4'}) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_1'], 2) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_2'], -1) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_4'], 1) self.assertEqual(self.model.matrix[Compound('C'), 'rxn_4'], -1) def test_flipable_model_view_matrix_get_item_after_double_flip(self): self.model.flip({'rxn_4', 'rxn_5'}) self.model.flip({'rxn_1', 'rxn_4', 'rxn_2'}) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_1'], -2) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_2'], 1) self.assertEqual(self.model.matrix[Compound('B'), 'rxn_2'], -1) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_4'], -1) self.assertEqual(self.model.matrix[Compound('C'), 'rxn_4'], 1) self.assertEqual(self.model.matrix[Compound('C'), 'rxn_5'], 1) self.assertEqual(self.model.matrix[Compound('D'), 'rxn_5'], -1) def test_flipable_model_view_limits_get_item_after_flip(self): self.model.flip({'rxn_1', 'rxn_2'}) self.assertEqual(self.model.limits['rxn_1'].bounds, (-1000, 0)) self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) self.assertEqual(self.model.limits['rxn_3'].bounds, (0, 1000)) def test_flipable_model_view_limits_set_item_after_flip(self): self.model.flip({'rxn_1'}) self.model.limits['rxn_1'].bounds = -20, 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (-20, 500)) self.model.flip({'rxn_1'}) self.assertEqual(self.model.limits['rxn_1'].bounds, (-500, 20))
class TestMetabolicModelFlipableView(unittest.TestCase): def setUp(self): # TODO use mock database instead of actual database self.database = DictDatabase() self.database.set_reaction("rxn_1", parse_reaction("=> (2) |A|")) self.database.set_reaction("rxn_2", parse_reaction("|A| <=> |B|")) self.database.set_reaction("rxn_3", parse_reaction("|A| => |D|")) self.database.set_reaction("rxn_4", parse_reaction("|A| => |C|")) self.database.set_reaction("rxn_5", parse_reaction("|C| => |D|")) self.database.set_reaction("rxn_6", parse_reaction("|D| =>")) model = MetabolicModel.load_model(self.database, self.database.reactions) self.model = FlipableModelView(model) def test_flipable_model_view_matrix_get_item_after_flip(self): self.model.flip({"rxn_4"}) self.assertEqual(self.model.matrix[Compound("A"), "rxn_1"], 2) self.assertEqual(self.model.matrix[Compound("A"), "rxn_2"], -1) self.assertEqual(self.model.matrix[Compound("A"), "rxn_4"], 1) self.assertEqual(self.model.matrix[Compound("C"), "rxn_4"], -1) def test_flipable_model_view_matrix_get_item_after_double_flip(self): self.model.flip({"rxn_4", "rxn_5"}) self.model.flip({"rxn_1", "rxn_4", "rxn_2"}) self.assertEqual(self.model.matrix[Compound("A"), "rxn_1"], -2) self.assertEqual(self.model.matrix[Compound("A"), "rxn_2"], 1) self.assertEqual(self.model.matrix[Compound("B"), "rxn_2"], -1) self.assertEqual(self.model.matrix[Compound("A"), "rxn_4"], -1) self.assertEqual(self.model.matrix[Compound("C"), "rxn_4"], 1) self.assertEqual(self.model.matrix[Compound("C"), "rxn_5"], 1) self.assertEqual(self.model.matrix[Compound("D"), "rxn_5"], -1) def test_flipable_model_view_limits_get_item_after_flip(self): self.model.flip({"rxn_1", "rxn_2"}) self.assertEqual(self.model.limits["rxn_1"].bounds, (-1000, 0)) self.assertEqual(self.model.limits["rxn_2"].bounds, (-1000, 1000)) self.assertEqual(self.model.limits["rxn_3"].bounds, (0, 1000)) def test_flipable_model_view_limits_set_item_after_flip(self): self.model.flip({"rxn_1"}) self.model.limits["rxn_1"].bounds = -20, 500 self.assertEqual(self.model.limits["rxn_1"].bounds, (-20, 500)) self.model.flip({"rxn_1"}) self.assertEqual(self.model.limits["rxn_1"].bounds, (-500, 20))
class TestMetabolicModelFlipableView(unittest.TestCase): def setUp(self): # TODO use mock database instead of actual database self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) model = MetabolicModel.load_model(self.database, self.database.reactions) self.model = FlipableModelView(model) def test_flipable_model_view_matrix_get_item_after_flip(self): self.model.flip({ 'rxn_4' }) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_1'], 2) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_2'], -1) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_4'], 1) self.assertEqual(self.model.matrix[Compound('C'), 'rxn_4'], -1) def test_flipable_model_view_matrix_get_item_after_double_flip(self): self.model.flip({ 'rxn_4', 'rxn_5' }) self.model.flip({ 'rxn_1', 'rxn_4', 'rxn_2' }) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_1'], -2) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_2'], 1) self.assertEqual(self.model.matrix[Compound('B'), 'rxn_2'], -1) self.assertEqual(self.model.matrix[Compound('A'), 'rxn_4'], -1) self.assertEqual(self.model.matrix[Compound('C'), 'rxn_4'], 1) self.assertEqual(self.model.matrix[Compound('C'), 'rxn_5'], 1) self.assertEqual(self.model.matrix[Compound('D'), 'rxn_5'], -1) def test_flipable_model_view_limits_get_item_after_flip(self): self.model.flip({ 'rxn_1', 'rxn_2' }) self.assertEqual(self.model.limits['rxn_1'].bounds, (-1000, 0)) self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) self.assertEqual(self.model.limits['rxn_3'].bounds, (0, 1000)) def test_flipable_model_view_limits_set_item_after_flip(self): self.model.flip({ 'rxn_1' }) self.model.limits['rxn_1'].bounds = -20, 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (-20, 500)) self.model.flip({ 'rxn_1' }) self.assertEqual(self.model.limits['rxn_1'].bounds, (-500, 20))
class TestRandomSparse(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('A[e] => B[e]')) self._database.set_reaction('rxn_2', parse_reaction('B[e] => C[e]')) self._database.set_reaction('rxn_3', parse_reaction('B[e] => D[e]')) self._database.set_reaction('rxn_4', parse_reaction('C[e] => E[e]')) self._database.set_reaction('rxn_5', parse_reaction('D[e] => E[e]')) self._database.set_reaction('rxn_6', parse_reaction('E[e] =>')) self._database.set_reaction('ex_A', parse_reaction('A[e] <=>')) self._mm = MetabolicModel.load_model(self._database, self._database.reactions) self._assoc = { 'rxn_1': boolean.Expression('gene_1'), 'rxn_2': boolean.Expression('gene_2 or gene_3'), 'rxn_5': boolean.Expression('gene_3 and gene_4') } self._obj_reaction = 'rxn_6' try: self._solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') self._prob = fluxanalysis.FluxBalanceProblem(self._mm, self._solver) def test_random_sparse_reaction_strategy(self): expected = [({'rxn_1', 'rxn_6', 'ex_A', 'rxn_2', 'rxn_4'}, {'rxn_3', 'rxn_5'}), ({'rxn_1', 'rxn_6', 'ex_A', 'rxn_3', 'rxn_5'}, {'rxn_2', 'rxn_4'})] strategy = randomsparse.ReactionDeletionStrategy(self._mm) essential, deleted = randomsparse.random_sparse(strategy, self._prob, self._obj_reaction, flux_threshold=100) self.assertTrue((essential, deleted) in expected) def test_random_sparse_gene_strategy(self): expected = [({'gene_1', 'gene_2'}, {'gene_3', 'gene_4'}), ({'gene_1', 'gene_3'}, {'gene_2', 'gene_4'})] strategy = randomsparse.GeneDeletionStrategy(self._mm, self._assoc) essential, deleted = randomsparse.random_sparse(strategy, self._prob, self._obj_reaction, flux_threshold=100) self.assertTrue((essential, deleted) in expected)
class TestGeneDeletionStrategy(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model( self._database, self._database.reactions) self._assoc = {'rxn_2': boolean.Expression('gene_1 or gene_2')} self._strategy = randomsparse.GeneDeletionStrategy( self._mm, self._assoc) def test_method_get_all(self): expected_total = {'gene_1', 'gene_2'} self.assertEqual(set(self._strategy.entities), expected_total) def test_method_tests_and_delete(self): expected_genes = {'gene_1', 'gene_2'} expected_reaction_set = {'rxn_2'} test_dict = {} for i, (gene, deleted_reac) in enumerate(self._strategy.iter_tests()): self._strategy.delete(gene, deleted_reac) if i == 0: self.assertEqual(deleted_reac, set()) else: self.assertEqual(deleted_reac, {'rxn_2'}) test_dict[gene] = deleted_reac self.assertTrue(all(x in test_dict for x in expected_genes)) self.assertTrue(expected_reaction_set in test_dict.values())
class TestGeneDeletionStrategy(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model(self._database, self._database.reactions) self._assoc = {'rxn_2': boolean.Expression('gene_1 or gene_2')} self._strategy = randomsparse.GeneDeletionStrategy( self._mm, self._assoc) def test_method_get_all(self): expected_total = {'gene_1', 'gene_2'} self.assertEqual(set(self._strategy.entities), expected_total) def test_method_tests_and_delete(self): expected_genes = {'gene_1', 'gene_2'} expected_reaction_set = {'rxn_2'} test_dict = {} for i, (gene, deleted_reac) in enumerate(self._strategy.iter_tests()): self._strategy.delete(gene, deleted_reac) if i == 0: self.assertEqual(deleted_reac, set()) else: self.assertEqual(deleted_reac, {'rxn_2'}) test_dict[gene] = deleted_reac self.assertTrue(all(x in test_dict for x in expected_genes)) self.assertTrue(expected_reaction_set in test_dict.values())
class TestFastGapFill(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model( self._database, self._database.reactions) try: self._solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_fastgapfill(self): core = {'rxn_2', 'rxn_3'} induced = fastgapfill.fastgapfill( self._mm, core, epsilon=0.001, solver=self._solver) self.assertEqual( set(induced), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4'})
class TestFluxBalance(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) self.solver = cplex.Solver() def test_flux_balance_rxn_1(self): fluxes = dict(fluxanalysis.flux_balance( self.model, 'rxn_1', tfba=False, solver=self.solver)) self.assertEqual(fluxes['rxn_1'], 500) self.assertEqual(fluxes['rxn_2'], 0) self.assertEqual(fluxes['rxn_6'], 1000) def test_flux_balance_rxn_2(self): fluxes = dict(fluxanalysis.flux_balance( self.model, 'rxn_2', tfba=False, solver=self.solver)) self.assertEqual(fluxes['rxn_2'], 0) def test_flux_balance_rxn_3(self): fluxes = dict(fluxanalysis.flux_balance( self.model, 'rxn_3', tfba=False, solver=self.solver)) self.assertEqual(fluxes['rxn_1'], 500) self.assertEqual(fluxes['rxn_2'], 0) self.assertEqual(fluxes['rxn_3'], 1000) self.assertEqual(fluxes['rxn_6'], 1000) def test_flux_balance_rxn_6(self): fluxes = dict(fluxanalysis.flux_balance( self.model, 'rxn_6', tfba=False, solver=self.solver)) self.assertEqual(fluxes['rxn_1'], 500) self.assertEqual(fluxes['rxn_2'], 0) self.assertEqual(fluxes['rxn_6'], 1000)
class TestGetExchangeReactions(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model(self._database, self._database.reactions) def test_get_exchange_reactions(self): expected_reactions = {'rxn_1', 'rxn_4'} self.assertEqual(set(randomsparse.get_exchange_reactions(self._mm)), expected_reactions)
class TestGetExchangeReactions(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model( self._database, self._database.reactions) def test_get_exchange_reactions(self): expected_reactions = {'rxn_1', 'rxn_4'} self.assertEqual( set(randomsparse.get_exchange_reactions(self._mm)), expected_reactions)
class TestGapfind(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_4', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_5', parse_reaction('|D| <=> |E|')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Unable to find an MILP solver for tests') def test_gapfind(self): self.model.remove_reaction('rxn_4') compounds = set(gapfind(self.model, self.solver)) self.assertEqual(compounds, {Compound('D'), Compound('E')}) def test_gapfill_add_reaction(self): core = set(self.model.reactions) - {'rxn_4'} blocked = {Compound('D'), Compound('E')} add, rev = gapfill(self.model, core, blocked, self.solver) self.assertEqual(set(rev), set()) self.assertEqual(set(add), {'rxn_4'}) def test_gapfill_reverse_reaction(self): self.model.database.set_reaction('rxn_4', parse_reaction('|D| => |C|')) core = set(self.model.reactions) blocked = {Compound('D'), Compound('E')} add, rev = gapfill(self.model, core, blocked, self.solver) self.assertEqual(set(rev), {'rxn_4'}) self.assertEqual(set(add), set())
class TestFlippingModel(unittest.TestCase): """Test fastcore on a model that has to flip""" def setUp(self): # TODO use mock model instead of actual model self.database = DictDatabase() self.database.set_reaction("rxn_1", parse_reaction("|A| <=>")) self.database.set_reaction("rxn_2", parse_reaction("|A| <=> |B|")) self.database.set_reaction("rxn_3", parse_reaction("|C| <=> |B|")) self.database.set_reaction("rxn_4", parse_reaction("|C| <=>")) self.model = MetabolicModel.load_model(self.database, self.database.reactions) self.solver = cplex.Solver() def test_fastcore_induced_model(self): core = {"rxn_2", "rxn_3"} self.assertEquals( set(fastcore.fastcore(self.model, core, 0.001, solver=self.solver)), {"rxn_1", "rxn_2", "rxn_3", "rxn_4"} )
class TestFlippingModel(unittest.TestCase): """Test fastcore on a model that has to flip""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self.database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_fastcore_induced_model(self): core = {'rxn_2', 'rxn_3'} self.assertEqual(set( fastcore.fastcore(self.model, core, 0.001, solver=self.solver)), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4'})
class TestFastGapFill(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model(self._database, self._database.reactions) try: self._solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_fastgapfill(self): core = {'rxn_2', 'rxn_3'} induced = fastgapfill.fastgapfill(self._mm, core, epsilon=0.001, solver=self._solver) self.assertEqual(set(induced), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4'})
class TestReactionDeletionStrategy(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model( self._database, self._database.reactions) self._strategy = randomsparse.ReactionDeletionStrategy(self._mm) def test_method_get_all(self): expected_total = {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4'} self.assertEqual(set(self._strategy.entities), expected_total) def test_method_tests(self): expected_reactions = { 'rxn_1': {'rxn_1'}, 'rxn_2': {'rxn_2'}, 'rxn_3': {'rxn_3'}, 'rxn_4': {'rxn_4'} } self.assertEqual(dict(self._strategy.iter_tests()), expected_reactions)
class TestReactionDeletionStrategy(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('|A| <=>')) self._database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self._database.set_reaction('rxn_3', parse_reaction('|C| <=> |B|')) self._database.set_reaction('rxn_4', parse_reaction('|C| <=>')) self._mm = MetabolicModel.load_model(self._database, self._database.reactions) self._strategy = randomsparse.ReactionDeletionStrategy(self._mm) def test_method_get_all(self): expected_total = {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4'} self.assertEqual(set(self._strategy.entities), expected_total) def test_method_tests(self): expected_reactions = { 'rxn_1': {'rxn_1'}, 'rxn_2': {'rxn_2'}, 'rxn_3': {'rxn_3'}, 'rxn_4': {'rxn_4'} } self.assertEqual(dict(self._strategy.iter_tests()), expected_reactions)
class TestMetabolicDatabase(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D[e]|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D[e]|')) self.database.set_reaction('rxn_6', parse_reaction('|D[e]| =>')) def test_reactions(self): self.assertEqual( set(self.database.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_compounds(self): self.assertEqual( set(self.database.compounds), {Compound('A'), Compound('B'), Compound('C'), Compound('D', 'e')}) def test_compartments(self): self.assertEqual(set(self.database.compartments), {None, 'e'}) def test_has_reaction_existing(self): self.assertTrue(self.database.has_reaction('rxn_3')) def test_has_reaction_not_existing(self): self.assertFalse(self.database.has_reaction('rxn_7')) def test_is_reversible_is_true(self): self.assertTrue(self.database.is_reversible('rxn_2')) def test_is_reversible_is_false(self): self.assertFalse(self.database.is_reversible('rxn_5')) def test_get_reaction_values(self): self.assertEqual(set(self.database.get_reaction_values('rxn_2')), { (Compound('A'), -1), (Compound('B'), 1) }) def test_get_compound_reactions(self): self.assertEqual(set(self.database.get_compound_reactions(Compound('A'))), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4' }) def test_reversible(self): self.assertEqual(set(self.database.reversible), { 'rxn_2' }) def test_get_reaction(self): reaction = parse_reaction('|A| => |D[e]|') self.assertEqual(self.database.get_reaction('rxn_3'), reaction) def test_set_reaction_with_zero_coefficient(self): reaction = Reaction( Direction.Both, [(Compound('A'), 1), (Compound('B'), 0)], [(Compound('C'), 1)]) self.database.set_reaction('rxn_new', reaction) self.assertNotIn('rxn_new', self.database.get_compound_reactions(Compound('B'))) def test_matrix_get_item(self): self.assertEqual(self.database.matrix[Compound('A'), 'rxn_1'], 2) self.assertEqual(self.database.matrix[Compound('A'), 'rxn_2'], -1) self.assertEqual(self.database.matrix[Compound('B'), 'rxn_2'], 1) self.assertEqual(self.database.matrix[Compound('A'), 'rxn_4'], -1) self.assertEqual(self.database.matrix[Compound('C'), 'rxn_4'], 1) self.assertEqual(self.database.matrix[Compound('C'), 'rxn_5'], -1) self.assertEqual(self.database.matrix[Compound('D', 'e'), 'rxn_5'], 1) def test_matrix_get_item_invalid_key(self): with self.assertRaises(KeyError): a = self.database.matrix[Compound('A'), 'rxn_5'] with self.assertRaises(KeyError): b = self.database.matrix['rxn_1'] def test_matrix_set_item_is_invalid(self): with self.assertRaises(TypeError): self.database.matrix[Compound('A'), 'rxn_1'] = 4 def test_matrix_iter(self): matrix_keys = { (Compound('A'), 'rxn_1'), (Compound('A'), 'rxn_2'), (Compound('B'), 'rxn_2'), (Compound('A'), 'rxn_3'), (Compound('D', 'e'), 'rxn_3'), (Compound('A'), 'rxn_4'), (Compound('C'), 'rxn_4'), (Compound('C'), 'rxn_5'), (Compound('D', 'e'), 'rxn_5'), (Compound('D', 'e'), 'rxn_6') } self.assertEqual(set(iter(self.database.matrix)), matrix_keys) def test_matrix_len(self): self.assertEqual(len(self.database.matrix), 10)
class TestAddReactions(unittest.TestCase): def setUp(self): self._database = DictDatabase() self._database.set_reaction('rxn_1', parse_reaction('A[e] => B[e]')) self._database.set_reaction('rxn_2', parse_reaction('B[e] => C[e]')) self._database.set_reaction('rxn_3', parse_reaction('B[e] <=> D[e]')) self._database.set_reaction('rxn_4', parse_reaction('C[e] <=> E[e]')) self._database.set_reaction('rxn_5', parse_reaction('D[e] => E[e]')) self._database.set_reaction('rxn_6', parse_reaction('E[e] =>')) self._database.set_reaction('ex_A', parse_reaction('A[e] <=>')) self._mm = MetabolicModel.load_model( self._database, self._database.reactions) self._assoc = { 'rxn_1': str('gene_1'), 'rxn_2': str('gene_2'), 'rxn_3': str('gene_5'), 'rxn_4': str('gene_3 or gene_4'), 'rxn_5': str('gene_5 and gene_6') } self._obj_reaction = 'rxn_6' try: self._solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Needs and integer programming solver') def test_reverse_model(self): test_associations = { 'rxn_1': str('gene_1'), 'rxn_2': str('gene_2'), 'rxn_3_forward': str('gene_5'), 'rxn_3_reverse': str('gene_5'), 'rxn_4_forward': str('gene_3 or gene_4'), 'rxn_4_reverse': str('gene_3 or gene_4'), 'rxn_5': str('gene_5 and gene_6') } mm_irreversible, reversible_gene_assoc, split_rxns = \ gimme.make_irreversible(self._mm, self._assoc, exclude_list=['ex_A', 'rxn_6']) self.assertEqual(split_rxns, set([('rxn_4_forward', 'rxn_4_reverse'), ('rxn_3_forward', 'rxn_3_reverse')])) self.assertEqual(reversible_gene_assoc, test_associations) self.assertEqual(set([i for i in mm_irreversible.reactions]), {'rxn_1', 'rxn_2', 'rxn_3_forward', 'rxn_3_reverse', 'rxn_4_forward', 'rxn_4_reverse', 'rxn_5', 'rxn_6', 'ex_A'}) def test_parse_transcriptome_file(self): f = ['gene\texpression', 'gene_1\t15', 'gene_2\t20', 'gene_3\t15', 'gene_4\t25', 'gene_5\t10', 'gene_6\t25'] d = gimme.parse_transcriptome_file(f, 20) self.assertEqual(d, {'gene_1': 5.0, 'gene_3': 5.0, 'gene_5': 10.0}) def test_get_rxn_value(self): mm_irreversible, reversible_gene_assoc, split_rxns =\ gimme.make_irreversible(self._mm, self._assoc, exclude_list=['ex_A', 'rxn_6']) f = ['gene\texpression', 'gene_1\t15', 'gene_2\t20', 'gene_3\t15', 'gene_4\t25', 'gene_5\t10', 'gene_6\t25'] d = gimme.parse_transcriptome_file(f, 20) root_single = gimme.get_rxn_value(boolean.Expression( reversible_gene_assoc['rxn_1'])._root, d) self.assertEqual(root_single, 5) root_and = gimme.get_rxn_value(boolean.Expression( reversible_gene_assoc['rxn_5'])._root, d) self.assertEqual(root_and, 10) root_none = gimme.get_rxn_value(boolean.Expression( reversible_gene_assoc['rxn_2'])._root, d) self.assertEqual(root_none, None) def test_gimme_model(self): f = ['gene\texpression', 'gene_1\t15', 'gene_2\t20', 'gene_3\t15', 'gene_4\t25', 'gene_5\t10', 'gene_6\t25'] threshold_dict = gimme.parse_transcriptome_file(f, 20) mm_irreversible, reversible_gene_assoc, split_rxns = \ gimme.make_irreversible(self._mm, self._assoc, exclude_list=['ex_A', 'rxn_6']) p = fluxanalysis.FluxBalanceProblem(mm_irreversible, generic.Solver()) final_model, used_exchange, below_threshold_ids, incon_score = \ gimme.solve_gimme_problem(p, mm_irreversible, 'rxn_6', reversible_gene_assoc, split_rxns, threshold_dict, MaybeRelative(20)) self.assertEqual(incon_score, 100) self.assertEqual(final_model, set(['rxn_1', 'rxn_2', 'rxn_4'])) self.assertEqual(below_threshold_ids, set(['rxn_1', 'rxn_3', 'rxn_5']))
class TestMassConsistency(unittest.TestCase): """Test mass consistency using a simple model""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_mass_consistent_is_consistent(self): exchange = { 'rxn_1', 'rxn_6' } self.assertTrue(massconsistency.is_consistent( self.model, self.solver, exchange, set())) def test_mass_inconsistent_is_consistent(self): exchange = { 'rxn_1', 'rxn_6' } self.database.set_reaction('rxn_7', parse_reaction('|D| => (2) |C|')) self.model.add_reaction('rxn_7') self.assertFalse(massconsistency.is_consistent( self.model, self.solver, exchange, set())) def test_mass_consistent_reactions_returns_compounds(self): exchange = { 'rxn_1', 'rxn_6' } _, compounds = massconsistency.check_reaction_consistency( self.model, exchange=exchange, solver=self.solver) for c, value in compounds: self.assertIn(c, self.model.compounds) self.assertGreaterEqual(value, 1.0) def test_mass_consistent_reactions_returns_reactions(self): exchange = { 'rxn_1', 'rxn_6' } reactions, _ = massconsistency.check_reaction_consistency( self.model, exchange=exchange, solver=self.solver) for r, residual in reactions: self.assertIn(r, self.model.reactions)
class TestMassConsistency(unittest.TestCase): """Test mass consistency using a simple model""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_mass_consistent_is_consistent(self): exchange = {'rxn_1', 'rxn_6'} self.assertTrue( massconsistency.is_consistent(self.model, self.solver, exchange, set())) def test_mass_inconsistent_is_consistent(self): exchange = {'rxn_1', 'rxn_6'} self.database.set_reaction('rxn_7', parse_reaction('|D| => (2) |C|')) self.model.add_reaction('rxn_7') self.assertFalse( massconsistency.is_consistent(self.model, self.solver, exchange, set())) def test_mass_consistent_reactions_returns_compounds(self): exchange = {'rxn_1', 'rxn_6'} _, compounds = massconsistency.check_reaction_consistency( self.model, exchange=exchange, solver=self.solver) for c, value in compounds: self.assertIn(c, self.model.compounds) self.assertGreaterEqual(value, 1.0) def test_mass_consistent_reactions_returns_reactions(self): exchange = {'rxn_1', 'rxn_6'} reactions, _ = massconsistency.check_reaction_consistency( self.model, exchange=exchange, solver=self.solver) for r, residual in reactions: self.assertIn(r, self.model.reactions)
class TestFluxBalance(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_flux_balance_rxn_1(self): fluxes = dict( fluxanalysis.flux_balance(self.model, 'rxn_1', tfba=False, solver=self.solver)) self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_flux_balance_rxn_2(self): fluxes = dict( fluxanalysis.flux_balance(self.model, 'rxn_2', tfba=False, solver=self.solver)) self.assertAlmostEqual(fluxes['rxn_2'], 0) def test_flux_balance_rxn_3(self): fluxes = dict( fluxanalysis.flux_balance(self.model, 'rxn_3', tfba=False, solver=self.solver)) self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_3'], 1000) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_flux_balance_rxn_6(self): fluxes = dict( fluxanalysis.flux_balance(self.model, 'rxn_6', tfba=False, solver=self.solver)) self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_flux_balance_object_maximize(self): p = fluxanalysis.FluxBalanceProblem(self.model, self.solver) p.maximize('rxn_6') self.assertAlmostEqual(p.get_flux('rxn_1'), 500) self.assertAlmostEqual(p.get_flux('rxn_2'), 0) self.assertAlmostEqual(p.get_flux('rxn_6'), 1000) def test_flux_balance_object_minimize_l1(self): p = fluxanalysis.FluxBalanceProblem(self.model, self.solver) p.prob.add_linear_constraints(p.get_flux_var('rxn_6') == 1000) p.minimize_l1() self.assertAlmostEqual(p.get_flux('rxn_1'), 500) self.assertAlmostEqual(p.get_flux('rxn_2'), 0) self.assertAlmostEqual(p.get_flux('rxn_3'), 1000) self.assertAlmostEqual(p.get_flux('rxn_4'), 0) self.assertAlmostEqual(p.get_flux('rxn_5'), 0) self.assertAlmostEqual(p.get_flux('rxn_6'), 1000) def test_flux_balance_object_minimize_l1_function(self): fluxes = dict( fluxanalysis.flux_minimization(self.model, {'rxn_6': 1000}, self.solver)) self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_3'], 1000) self.assertAlmostEqual(fluxes['rxn_4'], 0) self.assertAlmostEqual(fluxes['rxn_5'], 0) self.assertAlmostEqual(fluxes['rxn_6'], 1000) def test_flux_balance_object_max_min_l1(self): p = fluxanalysis.FluxBalanceProblem(self.model, self.solver) p.max_min_l1('rxn_6') self.assertAlmostEqual(p.get_flux('rxn_1'), 500) self.assertAlmostEqual(p.get_flux('rxn_2'), 0) self.assertAlmostEqual(p.get_flux('rxn_3'), 1000) self.assertAlmostEqual(p.get_flux('rxn_4'), 0) self.assertAlmostEqual(p.get_flux('rxn_5'), 0) self.assertAlmostEqual(p.get_flux('rxn_6'), 1000) # The temporary constraint on the reaction rxn_6 should go away. If # not, the next maximize will raise a FluxBalanceError. p.prob.add_linear_constraints(p.get_flux_var('rxn_1') == 10) p.maximize('rxn_6') self.assertAlmostEqual(p.get_flux('rxn_6'), 20) def test_flux_balance_object_max_min_l1_multiple(self): p = fluxanalysis.FluxBalanceProblem(self.model, self.solver) p.max_min_l1({'rxn_3': 1, 'rxn_4': 1, 'rxn_5': 1}) self.assertAlmostEqual(p.get_flux('rxn_1'), 500) self.assertAlmostEqual(p.get_flux('rxn_2'), 0) self.assertAlmostEqual(p.get_flux('rxn_3'), 0) self.assertAlmostEqual(p.get_flux('rxn_4'), 1000) self.assertAlmostEqual(p.get_flux('rxn_5'), 1000) self.assertAlmostEqual(p.get_flux('rxn_6'), 1000) def test_flux_balance_infeasible(self): self.model.limits['rxn_6'].lower = 500 self.model.limits['rxn_1'].upper = 10 p = fluxanalysis.FluxBalanceProblem(self.model, self.solver) try: p.maximize('rxn_6') except fluxanalysis.FluxBalanceError as e: self.assertFalse(e.result.unbounded) else: self.fail('FluxBalanceError was not raised!') def test_flux_balance_unbounded(self): unbounded = float('-inf'), float('inf') self.model.limits['rxn_1'].bounds = unbounded self.model.limits['rxn_3'].bounds = unbounded self.model.limits['rxn_6'].bounds = unbounded p = fluxanalysis.FluxBalanceProblem(self.model, self.solver) if self.solver.properties['name'] == 'qsoptex': # QSopt_ex returns status code 100 for this example. It seems that # it is unable to determine whether the problem is unbounded. self.skipTest('Skipping because of known issue with QSopt_ex') try: p.maximize('rxn_6') except fluxanalysis.FluxBalanceError as e: self.assertTrue(e.result.unbounded) else: self.fail('FluxBalanceError was not raised!')
class TestMetabolicModel(unittest.TestCase): def setUp(self): # TODO use mock database instead of actual database self.database = DictDatabase() self.database.set_reaction("rxn_1", parse_reaction("=> (2) |A|")) self.database.set_reaction("rxn_2", parse_reaction("|A| <=> |B|")) self.database.set_reaction("rxn_3", parse_reaction("|A| => |D[e]|")) self.database.set_reaction("rxn_4", parse_reaction("|A| => |C|")) self.database.set_reaction("rxn_5", parse_reaction("|C| => |D[e]|")) self.database.set_reaction("rxn_6", parse_reaction("|D[e]| =>")) self.model = MetabolicModel.load_model(self.database, self.database.reactions) def test_database_property(self): self.assertIs(self.model.database, self.database) def test_reaction_set(self): self.assertEqual(set(self.model.reactions), {"rxn_1", "rxn_2", "rxn_3", "rxn_4", "rxn_5", "rxn_6"}) def test_compound_set(self): self.assertEqual(set(self.model.compounds), {Compound("A"), Compound("B"), Compound("C"), Compound("D", "e")}) def test_compartments(self): self.assertEqual(set(self.model.compartments), {None, "e"}) def test_add_reaction_new(self): self.database.set_reaction("rxn_7", parse_reaction("|D[e]| => |E[e]|")) self.model.add_reaction("rxn_7") self.assertIn("rxn_7", set(self.model.reactions)) self.assertIn(Compound("E", "e"), set(self.model.compounds)) def test_add_reaction_existing(self): self.model.add_reaction("rxn_1") self.assertEqual(set(self.model.reactions), {"rxn_1", "rxn_2", "rxn_3", "rxn_4", "rxn_5", "rxn_6"}) self.assertEqual(set(self.model.compounds), {Compound("A"), Compound("B"), Compound("C"), Compound("D", "e")}) def test_add_reaction_invalid(self): with self.assertRaises(Exception): self.model.add_reaction("rxn_7") def test_remove_reaction_existing(self): self.model.remove_reaction("rxn_2") self.assertEqual(set(self.model.reactions), {"rxn_1", "rxn_3", "rxn_4", "rxn_5", "rxn_6"}) self.assertEqual(set(self.model.compounds), {Compound("A"), Compound("C"), Compound("D", "e")}) def test_is_reversible_on_reversible(self): self.assertTrue(self.model.is_reversible("rxn_2")) def test_is_reversible_on_irreversible(self): self.assertFalse(self.model.is_reversible("rxn_1")) self.assertFalse(self.model.is_reversible("rxn_3")) def test_is_exchange_on_exchange(self): self.assertTrue(self.model.is_exchange("rxn_1")) self.assertTrue(self.model.is_exchange("rxn_6")) def test_is_exchange_on_internal(self): self.assertFalse(self.model.is_exchange("rxn_2")) self.assertFalse(self.model.is_exchange("rxn_5")) def test_add_all_database_reactions(self): self.database.set_reaction("rxn_7", parse_reaction("|D| => |E|")) added = self.model.add_all_database_reactions() self.assertEqual(added, {"rxn_7"}) self.assertEqual(set(self.model.reactions), {"rxn_1", "rxn_2", "rxn_3", "rxn_4", "rxn_5", "rxn_6", "rxn_7"}) def test_add_all_database_reactions_none(self): added = self.model.add_all_database_reactions() self.assertEqual(added, set()) self.assertEqual(set(self.model.reactions), {"rxn_1", "rxn_2", "rxn_3", "rxn_4", "rxn_5", "rxn_6"}) def test_limits_get_item(self): self.assertEqual(self.model.limits["rxn_1"].bounds, (0, 1000)) self.assertEqual(self.model.limits["rxn_2"].bounds, (-1000, 1000)) self.assertEqual(self.model.limits["rxn_3"].bounds, (0, 1000)) def test_limits_get_item_invalid_key(self): with self.assertRaises(KeyError): a = self.model.limits["rxn_7"] def test_limits_set_item_is_invalid(self): with self.assertRaises(TypeError): self.model.limits["rxn_1"] = None def test_limits_set_upper_flux_bounds(self): self.model.limits["rxn_1"].upper = 500 self.assertEqual(self.model.limits["rxn_1"].bounds, (0, 500)) def test_limits_set_upper_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits["rxn_1"].upper = -20 def test_limits_delete_upper_flux_bounds(self): self.model.limits["rxn_1"].upper = 500 del self.model.limits["rxn_1"].upper self.assertEqual(self.model.limits["rxn_1"].bounds, (0, 1000)) def test_limits_delete_upper_not_set(self): del self.model.limits["rxn_1"].upper self.assertEqual(self.model.limits["rxn_1"].bounds, (0, 1000)) def test_limits_set_lower_flux_bounds(self): self.model.limits["rxn_1"].lower = 500 self.assertEqual(self.model.limits["rxn_1"].bounds, (500, 1000)) def test_limits_set_lower_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits["rxn_1"].lower = 1001 def test_limits_delete_lower_flux_bounds(self): self.model.limits["rxn_1"].lower = 500 del self.model.limits["rxn_1"].lower self.assertEqual(self.model.limits["rxn_1"].bounds, (0, 1000)) def test_limits_delete_lower_not_set(self): del self.model.limits["rxn_1"].lower self.assertEqual(self.model.limits["rxn_1"].bounds, (0, 1000)) def test_limits_set_both_flux_bounds(self): self.model.limits["rxn_2"].bounds = 1001, 1002 self.assertEqual(self.model.limits["rxn_2"].lower, 1001) self.assertEqual(self.model.limits["rxn_2"].upper, 1002) self.assertEqual(self.model.limits["rxn_2"].bounds, (1001, 1002)) def test_limits_set_both_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits["rxn_2"].bounds = 10, -1000 def test_limits_delete_both_flux_bounds(self): self.model.limits["rxn_2"].bounds = -10, 800 del self.model.limits["rxn_2"].bounds self.assertEqual(self.model.limits["rxn_2"].bounds, (-1000, 1000)) def test_limits_set_both_flux_bounds_delete_lower(self): self.model.limits["rxn_2"].bounds = -10, 800 del self.model.limits["rxn_2"].lower self.assertEqual(self.model.limits["rxn_2"].bounds, (-1000, 800)) def test_limits_set_both_flux_bounds_delete_upper(self): self.model.limits["rxn_2"].bounds = -10, 800 del self.model.limits["rxn_2"].upper self.assertEqual(self.model.limits["rxn_2"].bounds, (-10, 1000)) def test_limits_iter(self): self.assertEqual(set(iter(self.model.limits)), {"rxn_1", "rxn_2", "rxn_3", "rxn_4", "rxn_5", "rxn_6"}) def test_limits_len(self): self.assertEqual(len(self.model.limits), 6)
class TestMetabolicModel(unittest.TestCase): def setUp(self): # TODO use mock database instead of actual database self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D[e]|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D[e]|')) self.database.set_reaction('rxn_6', parse_reaction('|D[e]| =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) def test_database_property(self): self.assertIs(self.model.database, self.database) def test_reaction_set(self): self.assertEqual(set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_compound_set(self): self.assertEqual(set(self.model.compounds), {Compound('A'), Compound('B'), Compound('C'), Compound('D', 'e')}) def test_compartments(self): self.assertEqual(set(self.model.compartments), {None, 'e'}) def test_add_reaction_new(self): self.database.set_reaction('rxn_7', parse_reaction('|D[e]| => |E[e]|')) self.model.add_reaction('rxn_7') self.assertIn('rxn_7', set(self.model.reactions)) self.assertIn(Compound('E', 'e'), set(self.model.compounds)) def test_add_reaction_existing(self): self.model.add_reaction('rxn_1') self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) self.assertEqual( set(self.model.compounds), {Compound('A'), Compound('B'), Compound('C'), Compound('D', 'e')}) def test_add_reaction_invalid(self): with self.assertRaises(Exception): self.model.add_reaction('rxn_7') def test_remove_reaction_existing(self): self.model.remove_reaction('rxn_2') self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) self.assertEqual( set(self.model.compounds), {Compound('A'), Compound('C'), Compound('D', 'e')}) def test_is_reversible_on_reversible(self): self.assertTrue(self.model.is_reversible('rxn_2')) def test_is_reversible_on_irreversible(self): self.assertFalse(self.model.is_reversible('rxn_1')) self.assertFalse(self.model.is_reversible('rxn_3')) def test_is_exchange_on_exchange(self): self.assertTrue(self.model.is_exchange('rxn_1')) self.assertTrue(self.model.is_exchange('rxn_6')) def test_is_exchange_on_internal(self): self.assertFalse(self.model.is_exchange('rxn_2')) self.assertFalse(self.model.is_exchange('rxn_5')) def test_add_all_database_reactions(self): self.database.set_reaction('rxn_7', parse_reaction('|D| => |E|')) added = self.model.add_all_database_reactions() self.assertEqual(added, { 'rxn_7' }) self.assertEqual(set(self.model.reactions), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6', 'rxn_7' }) def test_add_all_database_reactions_none(self): added = self.model.add_all_database_reactions() self.assertEqual(added, set()) self.assertEqual(set(self.model.reactions), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6' }) def test_limits_get_item(self): self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) self.assertEqual(self.model.limits['rxn_3'].bounds, (0, 1000)) def test_limits_get_item_invalid_key(self): with self.assertRaises(KeyError): a = self.model.limits['rxn_7'] def test_limits_set_item_is_invalid(self): with self.assertRaises(TypeError): self.model.limits['rxn_1'] = None def test_limits_set_upper_flux_bounds(self): self.model.limits['rxn_1'].upper = 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 500)) def test_limits_set_upper_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_1'].upper = -20 def test_limits_delete_upper_flux_bounds(self): self.model.limits['rxn_1'].upper = 500 del self.model.limits['rxn_1'].upper self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_delete_upper_not_set(self): del self.model.limits['rxn_1'].upper self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_set_lower_flux_bounds(self): self.model.limits['rxn_1'].lower = 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (500, 1000)) def test_limits_set_lower_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_1'].lower = 1001 def test_limits_delete_lower_flux_bounds(self): self.model.limits['rxn_1'].lower = 500 del self.model.limits['rxn_1'].lower self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_delete_lower_not_set(self): del self.model.limits['rxn_1'].lower self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_set_both_flux_bounds(self): self.model.limits['rxn_2'].bounds = 1001, 1002 self.assertEqual(self.model.limits['rxn_2'].lower, 1001) self.assertEqual(self.model.limits['rxn_2'].upper, 1002) self.assertEqual(self.model.limits['rxn_2'].bounds, (1001, 1002)) def test_limits_set_both_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_2'].bounds = 10, -1000 def test_limits_delete_both_flux_bounds(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].bounds self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) def test_limits_set_both_flux_bounds_delete_lower(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].lower self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 800)) def test_limits_set_both_flux_bounds_delete_upper(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].upper self.assertEqual(self.model.limits['rxn_2'].bounds, (-10, 1000)) def test_limits_iter(self): self.assertEqual(set(iter(self.model.limits)), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6' }) def test_limits_len(self): self.assertEqual(len(self.model.limits), 6)
class TestMetabolicModel(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) A[c]')) self.database.set_reaction('rxn_2', parse_reaction('A[c] <=> B[c]')) self.database.set_reaction('rxn_3', parse_reaction('A[c] => D[e]')) self.database.set_reaction('rxn_4', parse_reaction('A[c] => C[c]')) self.database.set_reaction('rxn_5', parse_reaction('C[c] => D[e]')) self.database.set_reaction('rxn_6', parse_reaction('D[e] =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) def test_database_property(self): self.assertIs(self.model.database, self.database) def test_reaction_set(self): self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_compound_set(self): self.assertEqual( set(self.model.compounds), { Compound('A', 'c'), Compound('B', 'c'), Compound('C', 'c'), Compound('D', 'e') }) def test_compartments(self): self.assertEqual(set(self.model.compartments), {'c', 'e'}) def test_add_reaction_new(self): self.database.set_reaction('rxn_7', parse_reaction('D[e] => E[e]')) self.model.add_reaction('rxn_7') self.assertIn('rxn_7', set(self.model.reactions)) self.assertIn(Compound('E', 'e'), set(self.model.compounds)) def test_add_reaction_existing(self): self.model.add_reaction('rxn_1') self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) self.assertEqual( set(self.model.compounds), { Compound('A', 'c'), Compound('B', 'c'), Compound('C', 'c'), Compound('D', 'e') }) def test_add_reaction_invalid(self): with self.assertRaises(Exception): self.model.add_reaction('rxn_7') def test_remove_reaction_existing(self): self.model.remove_reaction('rxn_2') self.assertEqual(set(self.model.reactions), {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) self.assertEqual( set(self.model.compounds), {Compound('A', 'c'), Compound('C', 'c'), Compound('D', 'e')}) def test_is_reversible_on_reversible(self): self.assertTrue(self.model.is_reversible('rxn_2')) def test_is_reversible_on_irreversible(self): self.assertFalse(self.model.is_reversible('rxn_1')) self.assertFalse(self.model.is_reversible('rxn_3')) def test_is_exchange_on_exchange(self): self.assertTrue(self.model.is_exchange('rxn_1')) self.assertTrue(self.model.is_exchange('rxn_6')) def test_is_exchange_on_internal(self): self.assertFalse(self.model.is_exchange('rxn_2')) self.assertFalse(self.model.is_exchange('rxn_5')) def test_is_exchange_on_empty(self): self.database.set_reaction('rxn_7', Reaction(Direction.Both, [], [])) self.model.add_reaction('rxn_7') self.assertFalse(self.model.is_exchange('rxn_7')) def test_limits_get_item(self): self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) self.assertEqual(self.model.limits['rxn_3'].bounds, (0, 1000)) def test_limits_get_item_invalid_key(self): with self.assertRaises(KeyError): a = self.model.limits['rxn_7'] def test_limits_set_item_is_invalid(self): with self.assertRaises(TypeError): self.model.limits['rxn_1'] = None def test_limits_set_upper_flux_bounds(self): self.model.limits['rxn_1'].upper = 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 500)) def test_limits_set_upper_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_1'].upper = -20 def test_limits_delete_upper_flux_bounds(self): self.model.limits['rxn_1'].upper = 500 del self.model.limits['rxn_1'].upper self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_delete_upper_not_set(self): del self.model.limits['rxn_1'].upper self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_set_lower_flux_bounds(self): self.model.limits['rxn_1'].lower = 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (500, 1000)) def test_limits_set_lower_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_1'].lower = 1001 def test_limits_delete_lower_flux_bounds(self): self.model.limits['rxn_1'].lower = 500 del self.model.limits['rxn_1'].lower self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_delete_lower_not_set(self): del self.model.limits['rxn_1'].lower self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_set_both_flux_bounds(self): self.model.limits['rxn_2'].bounds = 1001, 1002 self.assertEqual(self.model.limits['rxn_2'].lower, 1001) self.assertEqual(self.model.limits['rxn_2'].upper, 1002) self.assertEqual(self.model.limits['rxn_2'].bounds, (1001, 1002)) def test_limits_set_both_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_2'].bounds = 10, -1000 def test_limits_delete_both_flux_bounds(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].bounds self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) def test_limits_set_both_flux_bounds_delete_lower(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].lower self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 800)) def test_limits_set_both_flux_bounds_delete_upper(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].upper self.assertEqual(self.model.limits['rxn_2'].bounds, (-10, 1000)) def test_limits_iter(self): self.assertEqual( set(iter(self.model.limits)), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_limits_len(self): self.assertEqual(len(self.model.limits), 6)
class TestMetabolicDatabase(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> 2 A')) self.database.set_reaction('rxn_2', parse_reaction('A <=> B')) self.database.set_reaction('rxn_3', parse_reaction('A => D[e]')) self.database.set_reaction('rxn_4', parse_reaction('A + 2 B => C')) self.database.set_reaction('rxn_5', parse_reaction('C => 3 D[e]')) self.database.set_reaction('rxn_6', parse_reaction('D[e] =>')) def test_reactions(self): self.assertEqual( set(self.database.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_compounds(self): self.assertEqual( set(self.database.compounds), {Compound('A'), Compound('B'), Compound('C'), Compound('D', 'e')}) def test_compartments(self): self.assertEqual(set(self.database.compartments), {None, 'e'}) def test_has_reaction_existing(self): self.assertTrue(self.database.has_reaction('rxn_3')) def test_has_reaction_not_existing(self): self.assertFalse(self.database.has_reaction('rxn_7')) def test_is_reversible_is_true(self): self.assertTrue(self.database.is_reversible('rxn_2')) def test_is_reversible_is_false(self): self.assertFalse(self.database.is_reversible('rxn_5')) def test_get_reaction_values(self): self.assertEqual(list(self.database.get_reaction_values('rxn_4')), [(Compound('A'), -1), (Compound('B'), -2), (Compound('C'), 1)]) def test_get_compound_reactions(self): self.assertEqual( set(self.database.get_compound_reactions(Compound('A'))), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4'}) def test_reversible(self): self.assertEqual(set(self.database.reversible), {'rxn_2'}) def test_get_reaction(self): reaction = parse_reaction('A + (2) B => C') self.assertEqual(self.database.get_reaction('rxn_4'), reaction) def test_set_reaction_with_zero_coefficient(self): reaction = Reaction(Direction.Both, [(Compound('A'), 1), (Compound('B'), 0)], [(Compound('C'), 1)]) self.database.set_reaction('rxn_new', reaction) self.assertNotIn('rxn_new', self.database.get_compound_reactions(Compound('B'))) def test_matrix_get_item(self): self.assertEqual(self.database.matrix[Compound('A'), 'rxn_1'], 2) self.assertEqual(self.database.matrix[Compound('A'), 'rxn_2'], -1) self.assertEqual(self.database.matrix[Compound('B'), 'rxn_2'], 1) self.assertEqual(self.database.matrix[Compound('A'), 'rxn_4'], -1) self.assertEqual(self.database.matrix[Compound('B'), 'rxn_4'], -2) self.assertEqual(self.database.matrix[Compound('C'), 'rxn_4'], 1) self.assertEqual(self.database.matrix[Compound('C'), 'rxn_5'], -1) self.assertEqual(self.database.matrix[Compound('D', 'e'), 'rxn_5'], 3) def test_matrix_get_item_invalid_key(self): with self.assertRaises(KeyError): a = self.database.matrix[Compound('A'), 'rxn_5'] with self.assertRaises(KeyError): b = self.database.matrix['rxn_1'] def test_matrix_set_item_is_invalid(self): with self.assertRaises(TypeError): self.database.matrix[Compound('A'), 'rxn_1'] = 4 def test_matrix_iter(self): matrix_keys = {(Compound('A'), 'rxn_1'), (Compound('A'), 'rxn_2'), (Compound('B'), 'rxn_2'), (Compound('A'), 'rxn_3'), (Compound('D', 'e'), 'rxn_3'), (Compound('A'), 'rxn_4'), (Compound('B'), 'rxn_4'), (Compound('C'), 'rxn_4'), (Compound('C'), 'rxn_5'), (Compound('D', 'e'), 'rxn_5'), (Compound('D', 'e'), 'rxn_6')} self.assertEqual(set(iter(self.database.matrix)), matrix_keys) def test_matrix_len(self): self.assertEqual(len(self.database.matrix), 11)
def setUp(self): database1 = DictDatabase() database1.set_reaction('rxn_1', parse_reaction('|A| => |B|')) database1.set_reaction('rxn_2', parse_reaction('|B| => |C| + |D|')) database1.set_reaction('rxn_3', parse_reaction('|D| <=> |E|')) database1.set_reaction('rxn_4', parse_reaction('|F| => |G|')) database2 = DictDatabase() database2.set_reaction('rxn_2', parse_reaction('|B| => |C|')) database2.set_reaction('rxn_3', parse_reaction('|C| => |D|')) database2.set_reaction('rxn_4', parse_reaction('|F| <=> |G|')) database2.set_reaction('rxn_5', parse_reaction('|G| + |I| <=> |H|')) self.database = ChainedDatabase(database2, database1)
class TestFastcoreSimpleVlassisModel(unittest.TestCase): """Test fastcore using the simple model in [Vlassis14]_.""" def setUp(self): # TODO use mock model instead of actual model self.database = DictDatabase() self.database.set_reaction("rxn_1", parse_reaction("=> (2) |A|")) self.database.set_reaction("rxn_2", parse_reaction("|A| <=> |B|")) self.database.set_reaction("rxn_3", parse_reaction("|A| => |D|")) self.database.set_reaction("rxn_4", parse_reaction("|A| => |C|")) self.database.set_reaction("rxn_5", parse_reaction("|C| => |D|")) self.database.set_reaction("rxn_6", parse_reaction("|D| =>")) self.model = MetabolicModel.load_model(self.database, self.database.reactions) self.solver = cplex.Solver() def test_lp10(self): result = fastcore.lp10( self.model, {"rxn_6"}, {"rxn_1", "rxn_3", "rxn_4", "rxn_5"}, solver=self.solver, epsilon=0.001, scaling=1e3 ) supp = set(fastcore.support(result, 0.999 * 0.001)) self.assertEqual(supp, {"rxn_1", "rxn_3", "rxn_6"}) def test_lp10_weighted(self): weights = {"rxn_3": 1} result = fastcore.lp10( self.model, {"rxn_6"}, {"rxn_1", "rxn_3", "rxn_4", "rxn_5"}, solver=self.solver, epsilon=0.001, scaling=1e3, weights=weights, ) supp = set(fastcore.support(result, 0.999 * 0.001)) self.assertEqual(supp, {"rxn_1", "rxn_3", "rxn_6"}) weights = {"rxn_3": 3} result = fastcore.lp10( self.model, {"rxn_6"}, {"rxn_1", "rxn_3", "rxn_4", "rxn_5"}, solver=self.solver, epsilon=0.001, scaling=1e3, weights=weights, ) supp = set(fastcore.support(result, 0.999 * 0.001)) self.assertEqual(supp, {"rxn_1", "rxn_4", "rxn_5", "rxn_6"}) def test_lp7(self): result = fastcore.lp7(self.model, set(self.model.reactions), 0.001, solver=self.solver) supp = set(fastcore.support_positive(result, 0.001 * 0.999)) self.assertEqual(supp, {"rxn_1", "rxn_3", "rxn_4", "rxn_5", "rxn_6"}) result = fastcore.lp7(self.model, {"rxn_5"}, 0.001, solver=self.solver) supp = set(fastcore.support_positive(result, 0.001 * 0.999)) self.assertEqual(supp, {"rxn_1", "rxn_4", "rxn_5", "rxn_6"}) def test_find_sparse_mode_singleton(self): core = {"rxn_1"} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3 ) ) self.assertEqual(mode, {"rxn_1", "rxn_3", "rxn_6"}) core = {"rxn_2"} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3 ) ) self.assertEqual(mode, set()) core = {"rxn_3"} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3 ) ) self.assertEqual(mode, {"rxn_1", "rxn_3", "rxn_6"}) core = {"rxn_4"} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3 ) ) self.assertEqual(mode, {"rxn_1", "rxn_4", "rxn_5", "rxn_6"}) core = {"rxn_5"} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3 ) ) self.assertEqual(mode, {"rxn_1", "rxn_4", "rxn_5", "rxn_6"}) core = {"rxn_6"} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3 ) ) self.assertEqual(mode, {"rxn_1", "rxn_3", "rxn_6"}) def test_find_sparse_mode_weighted(self): core = {"rxn_1"} weights = {"rxn_3": 1} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3, weights=weights, ) ) self.assertEqual(mode, {"rxn_1", "rxn_3", "rxn_6"}) weights = {"rxn_3": 3} mode = set( fastcore.find_sparse_mode( self.model, core, set(self.model.reactions) - core, solver=self.solver, epsilon=0.001, scaling=1e3, weights=weights, ) ) self.assertEqual(mode, {"rxn_1", "rxn_4", "rxn_5", "rxn_6"}) def test_fastcc_inconsistent(self): self.assertEqual(set(fastcore.fastcc(self.model, 0.001, solver=self.solver)), {"rxn_2"}) def test_fastcc_is_consistent_on_inconsistent(self): self.assertFalse(fastcore.fastcc_is_consistent(self.model, 0.001, solver=self.solver)) def test_fastcc_is_consistent_on_consistent(self): self.model.remove_reaction("rxn_2") self.assertTrue(fastcore.fastcc_is_consistent(self.model, 0.001, solver=self.solver)) def test_fastcc_consistent_subset(self): self.assertEqual( fastcore.fastcc_consistent_subset(self.model, 0.001, solver=self.solver), set(["rxn_1", "rxn_3", "rxn_4", "rxn_5", "rxn_6"]), ) def test_fastcore_global_inconsistent(self): self.database.set_reaction("rxn_7", parse_reaction("|E| <=>")) self.model.add_reaction("rxn_7") with self.assertRaises(fastcore.FastcoreError): fastcore.fastcore(self.model, {"rxn_7"}, 0.001, solver=self.solver)
class TestFluxRandomization(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.database.set_reaction('rxn_7', parse_reaction('|E| => |F|')) self.database.set_reaction('rxn_8', parse_reaction('|F| => |E|')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_flux_randomization(self): fluxes = dict( fluxanalysis.flux_randomization(self.model, {'rxn_6': 1000}, False, self.solver)) self.assertAlmostEqual(fluxes['rxn_1'], 500) self.assertAlmostEqual(fluxes['rxn_2'], 0) self.assertAlmostEqual(fluxes['rxn_3'] + fluxes['rxn_4'], 1000) self.assertAlmostEqual(fluxes['rxn_6'], 1000) # Cycle self.assertGreaterEqual(fluxes['rxn_7'], 0) self.assertGreaterEqual(fluxes['rxn_8'], 0) self.assertLessEqual(fluxes['rxn_7'], 1000) self.assertLessEqual(fluxes['rxn_8'], 1000)
class TestFluxConsistencyThermodynamic(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.database.set_reaction('rxn_7', parse_reaction('|E| => |F|')) self.database.set_reaction('rxn_8', parse_reaction('|F| => |E|')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Unable to find an MILP solver for tests') def test_check_on_inconsistent_with_thermodynamic_constraints(self): self.model.remove_reaction('rxn_2') core = self.model.reactions inconsistent = set( fluxanalysis.consistency_check(self.model, core, epsilon=0.001, tfba=True, solver=self.solver)) self.assertEqual(inconsistent, {'rxn_7', 'rxn_8'})
class TestFastcoreSimpleVlassisModel(unittest.TestCase): """Test fastcore using the simple model in [Vlassis14]_.""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_lp10(self): p = fastcore.FastcoreProblem(self.model, self.solver, epsilon=0.001) scaling = 1000 p.lp10({'rxn_6'}, {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5'}) supp = set(reaction_id for reaction_id in self.model.reactions if abs(p.get_flux(reaction_id)) >= 0.999 * 0.001 / scaling) self.assertEqual(supp, { 'rxn_1', 'rxn_3', 'rxn_6' }) def test_lp10_weighted(self): p = fastcore.FastcoreProblem(self.model, self.solver, epsilon=0.001) scaling = 1000 weights = {'rxn_3': 1} p.lp10({'rxn_6'}, {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5'}, weights=weights) supp = set(reaction_id for reaction_id in self.model.reactions if abs(p.get_flux(reaction_id)) >= 0.999 * 0.001 / scaling) self.assertEqual(supp, {'rxn_1', 'rxn_3', 'rxn_6'}) weights = {'rxn_3': 3} p.lp10({'rxn_6'}, {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5'}, weights=weights) supp = set(reaction_id for reaction_id in self.model.reactions if abs(p.get_flux(reaction_id)) >= 0.999 * 0.001 / scaling) self.assertEqual(supp, {'rxn_1', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_lp7(self): p = fastcore.FastcoreProblem(self.model, self.solver, epsilon=0.001) p.lp7(set(self.model.reactions)) supp = set(reaction_id for reaction_id in self.model.reactions if p.get_flux(reaction_id) >= 0.001*0.999) self.assertEqual(supp, {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) p.lp7({'rxn_5'}) supp = set(reaction_id for reaction_id in self.model.reactions if p.get_flux(reaction_id) >= 0.001*0.999) # Test that the support contains at least the given reactions self.assertLessEqual({'rxn_4', 'rxn_5', 'rxn_6'}, supp) def test_find_sparse_mode_singleton(self): p = fastcore.FastcoreProblem(self.model, self.solver, epsilon=0.001) core = {'rxn_1'} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3)) self.assertEqual(mode, {'rxn_1', 'rxn_3', 'rxn_6'}) core = {'rxn_2'} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3)) self.assertEqual(mode, set()) core = {'rxn_3'} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3)) self.assertEqual(mode, {'rxn_1', 'rxn_3', 'rxn_6'}) core = {'rxn_4'} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3)) self.assertEqual(mode, {'rxn_1', 'rxn_4', 'rxn_5', 'rxn_6'}) core = {'rxn_5'} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3)) self.assertEqual(mode, {'rxn_1', 'rxn_4', 'rxn_5', 'rxn_6'}) core = {'rxn_6'} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3)) self.assertEqual(mode, {'rxn_1', 'rxn_3', 'rxn_6'}) def test_find_sparse_mode_weighted(self): p = fastcore.FastcoreProblem(self.model, self.solver, epsilon=0.001) core = {'rxn_1'} weights = {'rxn_3': 1} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3, weights=weights)) self.assertEqual(mode, {'rxn_1', 'rxn_3', 'rxn_6'}) weights = {'rxn_3': 3} mode = set(p.find_sparse_mode( core, set(self.model.reactions) - core, scaling=1e3, weights=weights)) self.assertEqual(mode, {'rxn_1', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_fastcc_inconsistent(self): self.assertEqual( set(fastcore.fastcc(self.model, 0.001, solver=self.solver)), {'rxn_2'}) def test_fastcc_is_consistent_on_inconsistent(self): self.assertFalse(fastcore.fastcc_is_consistent( self.model, 0.001, solver=self.solver)) def test_fastcc_is_consistent_on_consistent(self): self.model.remove_reaction('rxn_2') self.assertTrue(fastcore.fastcc_is_consistent( self.model, 0.001, solver=self.solver)) def test_fastcc_consistent_subset(self): self.assertEqual(fastcore.fastcc_consistent_subset( self.model, 0.001, solver=self.solver), set(['rxn_1', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'])) def test_fastcore_global_inconsistent(self): self.database.set_reaction('rxn_7', parse_reaction('|E| <=>')) self.model.add_reaction('rxn_7') with self.assertRaises(fastcore.FastcoreError): fastcore.fastcore(self.model, {'rxn_7'}, 0.001, solver=self.solver)
class TestFluxVariability(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.database.set_reaction('rxn_7', parse_reaction('|E| => |F|')) self.database.set_reaction('rxn_8', parse_reaction('|F| => |E|')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) self.model.limits['rxn_5'].upper = 100 try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_flux_variability(self): fluxes = dict( fluxanalysis.flux_variability(self.model, self.model.reactions, {'rxn_6': 200}, tfba=False, solver=self.solver)) for bounds in itervalues(fluxes): self.assertEqual(len(bounds), 2) self.assertAlmostEqual(fluxes['rxn_1'][0], 100) self.assertAlmostEqual(fluxes['rxn_2'][0], 0) self.assertAlmostEqual(fluxes['rxn_2'][1], 0) self.assertAlmostEqual(fluxes['rxn_5'][0], 0) self.assertAlmostEqual(fluxes['rxn_5'][1], 100) self.assertAlmostEqual(fluxes['rxn_6'][0], 200) self.assertGreater(fluxes['rxn_7'][1], 0) self.assertGreater(fluxes['rxn_8'][1], 0) def test_flux_variability_unbounded(self): self.model.limits['rxn_7'].upper = float('inf') self.model.limits['rxn_8'].upper = float('inf') if self.solver.properties['name'] == 'qsoptex': # QSopt_ex returns status code 100 for this example. It seems that # it is unable to determine whether the problem is unbounded. self.skipTest('Skipping because of known issue with QSopt_ex') fluxes = dict( fluxanalysis.flux_variability(self.model, self.model.reactions, {'rxn_6': 200}, tfba=False, solver=self.solver)) for bounds in itervalues(fluxes): self.assertEqual(len(bounds), 2) self.assertAlmostEqual(fluxes['rxn_6'][0], 200) self.assertAlmostEqual(fluxes['rxn_7'][0], 0) self.assertEqual(fluxes['rxn_7'][1], float('inf')) self.assertAlmostEqual(fluxes['rxn_8'][0], 0) self.assertEqual(fluxes['rxn_8'][1], float('inf'))
class TestMetabolicModel(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) A[c]')) self.database.set_reaction('rxn_2', parse_reaction('A[c] <=> B[c]')) self.database.set_reaction('rxn_3', parse_reaction('A[c] => D[e]')) self.database.set_reaction('rxn_4', parse_reaction('A[c] => C[c]')) self.database.set_reaction('rxn_5', parse_reaction('C[c] => D[e]')) self.database.set_reaction('rxn_6', parse_reaction('D[e] =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) def test_database_property(self): self.assertIs(self.model.database, self.database) def test_reaction_set(self): self.assertEqual(set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_compound_set(self): self.assertEqual(set(self.model.compounds), {Compound('A', 'c'), Compound('B', 'c'), Compound('C', 'c'), Compound('D', 'e')}) def test_compartments(self): self.assertEqual(set(self.model.compartments), {'c', 'e'}) def test_add_reaction_new(self): self.database.set_reaction('rxn_7', parse_reaction('D[e] => E[e]')) self.model.add_reaction('rxn_7') self.assertIn('rxn_7', set(self.model.reactions)) self.assertIn(Compound('E', 'e'), set(self.model.compounds)) def test_add_reaction_existing(self): self.model.add_reaction('rxn_1') self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) self.assertEqual(set(self.model.compounds), { Compound('A', 'c'), Compound('B', 'c'), Compound('C', 'c'), Compound('D', 'e')}) def test_add_reaction_invalid(self): with self.assertRaises(Exception): self.model.add_reaction('rxn_7') def test_remove_reaction_existing(self): self.model.remove_reaction('rxn_2') self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) self.assertEqual(set(self.model.compounds), { Compound('A', 'c'), Compound('C', 'c'), Compound('D', 'e')}) def test_is_reversible_on_reversible(self): self.assertTrue(self.model.is_reversible('rxn_2')) def test_is_reversible_on_irreversible(self): self.assertFalse(self.model.is_reversible('rxn_1')) self.assertFalse(self.model.is_reversible('rxn_3')) def test_is_exchange_on_exchange(self): self.assertTrue(self.model.is_exchange('rxn_1')) self.assertTrue(self.model.is_exchange('rxn_6')) def test_is_exchange_on_internal(self): self.assertFalse(self.model.is_exchange('rxn_2')) self.assertFalse(self.model.is_exchange('rxn_5')) def test_is_exchange_on_empty(self): self.database.set_reaction('rxn_7', Reaction(Direction.Both, [], [])) self.model.add_reaction('rxn_7') self.assertFalse(self.model.is_exchange('rxn_7')) def test_limits_get_item(self): self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) self.assertEqual(self.model.limits['rxn_3'].bounds, (0, 1000)) def test_limits_get_item_invalid_key(self): with self.assertRaises(KeyError): a = self.model.limits['rxn_7'] def test_limits_set_item_is_invalid(self): with self.assertRaises(TypeError): self.model.limits['rxn_1'] = None def test_limits_set_upper_flux_bounds(self): self.model.limits['rxn_1'].upper = 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 500)) def test_limits_set_upper_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_1'].upper = -20 def test_limits_delete_upper_flux_bounds(self): self.model.limits['rxn_1'].upper = 500 del self.model.limits['rxn_1'].upper self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_delete_upper_not_set(self): del self.model.limits['rxn_1'].upper self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_set_lower_flux_bounds(self): self.model.limits['rxn_1'].lower = 500 self.assertEqual(self.model.limits['rxn_1'].bounds, (500, 1000)) def test_limits_set_lower_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_1'].lower = 1001 def test_limits_delete_lower_flux_bounds(self): self.model.limits['rxn_1'].lower = 500 del self.model.limits['rxn_1'].lower self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_delete_lower_not_set(self): del self.model.limits['rxn_1'].lower self.assertEqual(self.model.limits['rxn_1'].bounds, (0, 1000)) def test_limits_set_both_flux_bounds(self): self.model.limits['rxn_2'].bounds = 1001, 1002 self.assertEqual(self.model.limits['rxn_2'].lower, 1001) self.assertEqual(self.model.limits['rxn_2'].upper, 1002) self.assertEqual(self.model.limits['rxn_2'].bounds, (1001, 1002)) def test_limits_set_both_flux_bounds_to_invalid(self): with self.assertRaises(ValueError): self.model.limits['rxn_2'].bounds = 10, -1000 def test_limits_delete_both_flux_bounds(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].bounds self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 1000)) def test_limits_set_both_flux_bounds_delete_lower(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].lower self.assertEqual(self.model.limits['rxn_2'].bounds, (-1000, 800)) def test_limits_set_both_flux_bounds_delete_upper(self): self.model.limits['rxn_2'].bounds = -10, 800 del self.model.limits['rxn_2'].upper self.assertEqual(self.model.limits['rxn_2'].bounds, (-10, 1000)) def test_limits_iter(self): self.assertEqual(set(iter(self.model.limits)), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_limits_len(self): self.assertEqual(len(self.model.limits), 6)
class TestGapfind(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_4', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_5', parse_reaction('|D| <=> |E|')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Unable to find an MILP solver for tests') def test_gapfind(self): self.model.remove_reaction('rxn_4') compounds = set(gapfind(self.model, self.solver, epsilon=0.1)) self.assertEqual(compounds, {Compound('D'), Compound('E')}) def test_gapfill_add_reaction(self): core = set(self.model.reactions) - {'rxn_4'} blocked = {Compound('D'), Compound('E')} add, rev = gapfill( self.model, core, blocked, {}, self.solver, epsilon=0.1) self.assertEqual(set(rev), set()) self.assertEqual(set(add), {'rxn_4'}) def test_gapfill_exclude_addition(self): core = set(self.model.reactions) - {'rxn_4'} blocked = {Compound('D'), Compound('E')} exclude = {'rxn_4'} with self.assertRaises(GapFillError): gapfill(self.model, core, blocked, exclude, self.solver, epsilon=0.1) def test_gapfill_reverse_reaction(self): self.model.database.set_reaction('rxn_4', parse_reaction('|D| => |C|')) core = set(self.model.reactions) blocked = {Compound('D'), Compound('E')} add, rev = gapfill( self.model, core, blocked, {}, self.solver, epsilon=0.1, allow_bounds_expansion=True) self.assertEqual(set(rev), {'rxn_4'}) self.assertEqual(set(add), set()) def test_gapfill_reverse_reaction_not_allowed(self): self.model.database.set_reaction('rxn_4', parse_reaction('|D| => |C|')) core = set(self.model.reactions) blocked = {Compound('D'), Compound('E')} with self.assertRaises(GapFillError): add, rev = gapfill( self.model, core, blocked, {}, self.solver, epsilon=0.1) def test_gapfill_exclude_reversal(self): self.model.database.set_reaction('rxn_4', parse_reaction('D => C')) core = set(self.model.reactions) blocked = {Compound('D'), Compound('E')} exclude = {'rxn_4'} with self.assertRaises(GapFillError): gapfill(self.model, core, blocked, exclude, self.solver, epsilon=0.1)
class TestAddReactions(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) A[c]')) self.database.set_reaction('rxn_2', parse_reaction('A[c] <=> B[c]')) self.database.set_reaction('rxn_3', parse_reaction('A[c] => D[e]')) self.database.set_reaction('rxn_4', parse_reaction('A[c] => C[c]')) self.database.set_reaction('rxn_5', parse_reaction('C[c] => D[e]')) self.database.set_reaction('rxn_6', parse_reaction('D[e] =>')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) def test_add_all_database_reactions(self): # Should get added self.database.set_reaction('rxn_7', parse_reaction('D[c] => E[c]')) # Not added because of compartment self.database.set_reaction('rxn_8', parse_reaction('D[c] => E[p]')) added = gapfilling.add_all_database_reactions(self.model, {'c', 'e'}) self.assertEqual(added, {'rxn_7'}) self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6', 'rxn_7'}) def test_add_all_database_reactions_none(self): added = gapfilling.add_all_database_reactions(self.model, {'c', 'e'}) self.assertEqual(added, set()) self.assertEqual( set(self.model.reactions), {'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_add_all_transport_reactions(self): added = gapfilling.add_all_transport_reactions(self.model, {('e', 'c')}) for reaction in added: compartments = tuple( c.compartment for c, _ in self.model.get_reaction_values(reaction)) self.assertEqual(len(compartments), 2) self.assertTrue('e' in compartments) self.assertTrue(compartments[0] != compartments[1])
class TestFluxVariabilityThermodynamic(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) |A|')) self.database.set_reaction('rxn_2', parse_reaction('|A| <=> |B|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |D|')) self.database.set_reaction('rxn_4', parse_reaction('|A| => |C|')) self.database.set_reaction('rxn_5', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_6', parse_reaction('|D| =>')) self.database.set_reaction('rxn_7', parse_reaction('|E| => |F|')) self.database.set_reaction('rxn_8', parse_reaction('|F| => |E|')) self.model = MetabolicModel.load_model(self.database, self.database.reactions) self.model.limits['rxn_5'].upper = 100 try: self.solver = generic.Solver(integer=True) except generic.RequirementsError: self.skipTest('Unable to find an MILP solver for tests') def test_flux_variability_thermodynamic(self): fluxes = dict( fluxanalysis.flux_variability(self.model, self.model.reactions, {'rxn_6': 200}, tfba=True, solver=self.solver)) self.assertAlmostEqual(fluxes['rxn_1'][0], 100) self.assertAlmostEqual(fluxes['rxn_2'][0], 0) self.assertAlmostEqual(fluxes['rxn_2'][1], 0) self.assertAlmostEqual(fluxes['rxn_5'][0], 0) self.assertAlmostEqual(fluxes['rxn_5'][1], 100) self.assertAlmostEqual(fluxes['rxn_6'][0], 200) self.assertAlmostEqual(fluxes['rxn_7'][1], 0) self.assertAlmostEqual(fluxes['rxn_8'][1], 0)
class TestAddReactions(unittest.TestCase): def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('=> (2) A[c]')) self.database.set_reaction('rxn_2', parse_reaction('A[c] <=> B[c]')) self.database.set_reaction('rxn_3', parse_reaction('A[c] => D[e]')) self.database.set_reaction('rxn_4', parse_reaction('A[c] => C[c]')) self.database.set_reaction('rxn_5', parse_reaction('C[c] => D[e]')) self.database.set_reaction('rxn_6', parse_reaction('D[e] =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) def test_add_all_database_reactions(self): # Should get added self.database.set_reaction('rxn_7', parse_reaction('D[c] => E[c]')) # Not added because of compartment self.database.set_reaction('rxn_8', parse_reaction('D[c] => E[p]')) added = gapfilling.add_all_database_reactions(self.model, {'c', 'e'}) self.assertEqual(added, {'rxn_7'}) self.assertEqual(set(self.model.reactions), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6', 'rxn_7' }) def test_add_all_database_reactions_none(self): added = gapfilling.add_all_database_reactions(self.model, {'c', 'e'}) self.assertEqual(added, set()) self.assertEqual(set(self.model.reactions), { 'rxn_1', 'rxn_2', 'rxn_3', 'rxn_4', 'rxn_5', 'rxn_6'}) def test_add_all_transport_reactions(self): added = gapfilling.add_all_transport_reactions( self.model, {('e', 'c')}) for reaction in added: compartments = tuple(c.compartment for c, _ in self.model.get_reaction_values(reaction)) self.assertEqual(len(compartments), 2) self.assertTrue('e' in compartments) self.assertTrue(compartments[0] != compartments[1])
class TestFluxCouplingBurgardModel(unittest.TestCase): """Test case based on the simple model in [Burgard04]_.""" def setUp(self): self.database = DictDatabase() self.database.set_reaction('rxn_1', parse_reaction('|A| => |B|')) self.database.set_reaction('rxn_2', parse_reaction('|B| => |G|')) self.database.set_reaction('rxn_3', parse_reaction('|A| => |G|')) self.database.set_reaction('rxn_4', parse_reaction('|B| => |H|')) self.database.set_reaction('rxn_5', parse_reaction('|B| => |C| + |F|')) self.database.set_reaction('rxn_6', parse_reaction('|C| => |D|')) self.database.set_reaction('rxn_7', parse_reaction('|E| <=> |D|')) self.database.set_reaction('rxn_9', parse_reaction('|I| => |J|')) self.database.set_reaction('rxn_10', parse_reaction('|J| => |K|')) self.database.set_reaction('rxn_A', parse_reaction('=> |A|')) self.database.set_reaction('rxn_G', parse_reaction('|G| =>')) self.database.set_reaction('rxn_E', parse_reaction('|E| =>')) self.database.set_reaction( 'rxn_bio', parse_reaction('|D| + (2.5) |F| =>')) self.model = MetabolicModel.load_model( self.database, self.database.reactions) try: self.solver = generic.Solver() except generic.RequirementsError: self.skipTest('Unable to find an LP solver for tests') def test_flux_coupling(self): if self.solver.properties['name'] == 'qsoptex': self.skipTest('Flux coupling with QSopt_ex is very slow') fcp = fluxcoupling.FluxCouplingProblem(self.model, {}, self.solver) reactions = sorted(self.model.reactions) couplings = {} for r1 in reactions: for r2 in reactions: couplings[r1, r2] = fcp.solve(r1, r2) inconsistent = {'rxn_4', 'rxn_9', 'rxn_10'} coupled_set = {'rxn_5', 'rxn_6', 'rxn_7', 'rxn_bio', 'rxn_E'} for i, r1 in enumerate(reactions): for r2 in reactions[i:]: if r1 == r2: # A reaction is always fully coupled to itself # unless it is inconsistent. lower, upper = couplings[r1, r2] if r1 in inconsistent: self.assertEqual((lower, upper), (None, None)) else: print('{}, {}: {}, {}'.format(r1, r2, lower, upper)) self.assertAlmostEqual(lower, upper) elif r1 in inconsistent or r2 in inconsistent: # Couplings with inconsistent reactions are always # fully coupled at 0.0 or uncoupled. coupling = couplings[r1, r2] self.assertIn(coupling, ((0.0, 0.0), (None, None))) elif r1 in coupled_set and r2 in coupled_set: lower, upper = couplings[r1, r2] self.assertAlmostEqual(lower, upper) else: # At least one of the values must be 0 or None if the # reactions are not in the coupled set. coupling = couplings[r1, r2] self.assertTrue(any(v in (0.0, None) for v in coupling)) # Couplings with rxn_7 are negative for r in coupled_set: if r != 'rxn_7': self.assertLess(couplings['rxn_7', r][0], 0.0)