Skip to content

Commit

Permalink
always pass time to _check_species() so it can be properly reported (…
Browse files Browse the repository at this point in the history
…and formatted)
  • Loading branch information
artgoldberg committed Dec 29, 2020
1 parent b65cafd commit 6b6a7aa
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 34 deletions.
3 changes: 1 addition & 2 deletions tests/submodels/test_dfba.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,7 @@ def test_run_fba_solver(self):
dfba_submodel_4.time = 0.1
dfba_submodel_4.time_step = 1.
with self.assertRaisesRegexp(DynamicMultialgorithmError,
re.escape("0.1: "
"DfbaSubmodel metabolism: No optimal solution found: "
re.escape("DfbaSubmodel metabolism: No optimal solution found: "
"'infeasible' for time step [0.1, 1.1]")):
dfba_submodel_4.run_fba_solver()

Expand Down
31 changes: 17 additions & 14 deletions tests/submodels/test_multiple_submodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class TestMultipleSubmodels(unittest.TestCase):

def setUp(self):
self.test_dir = tempfile.mkdtemp()
self.model = Reader().run(self.EXAMPLE_WC_MODEL, validate=True)[wc_lang.Model][0]
with EnvironUtils.temp_config_env([(['wc_lang', 'validation', 'validate_element_charge_balance'], 'False')]):
self.model = Reader().run(self.EXAMPLE_WC_MODEL, validate=True)[wc_lang.Model][0]

def tearDown(self):
shutil.rmtree(self.test_dir)
Expand Down Expand Up @@ -98,16 +99,18 @@ def test_run_submodel(self):
verbosity='status'))
options = {'DfbaSubmodel': dfba_options}
for i in range(N):
model = Reader().run(self.EXAMPLE_WC_MODEL, validate=True)[wc_lang.Model][0]
print(util.get_model_summary(model))
print(f"\n*** RUN {i} with seed {seeds[i]} ***")
try:
# TODO: remove when 4_submodel_MP_model.xlsx has an accounted mass fraction below the default
with EnvironUtils.temp_config_env([(['wc_sim', 'multialgorithm', 'max_allowed_init_accounted_fraction'],
str(3.0))]):
simulation_rv = self.run_simulation(wc_sim.Simulation(model), max_time=max_time, seed=seeds[i],
options=options)
print(f"Simulated {simulation_rv.num_events} events")
print(f"Results in '{simulation_rv.results_dir}'")
except wc_sim.multialgorithm_errors.MultialgorithmError as e:
print(f"MultialgorithmError {e}")
with EnvironUtils.temp_config_env([(['wc_lang', 'validation', 'validate_element_charge_balance'], 'False')]):
model = Reader().run(self.EXAMPLE_WC_MODEL, validate=True)[wc_lang.Model][0]
print(util.get_model_summary(model))
print(f"\n*** RUN {i} with seed {seeds[i]} ***")
try:
# TODO: remove when 4_submodel_MP_model.xlsx has an accounted mass fraction below the default
with EnvironUtils.temp_config_env([(['wc_sim', 'multialgorithm',
'max_allowed_init_accounted_fraction'],
str(3.0))]):
simulation_rv = self.run_simulation(wc_sim.Simulation(model), max_time=max_time, seed=seeds[i],
options=options)
print(f"Simulated {simulation_rv.num_events} events")
print(f"Results in '{simulation_rv.results_dir}'")
except wc_sim.multialgorithm_errors.MultialgorithmError as e:
print(f"MultialgorithmError {e}")
17 changes: 9 additions & 8 deletions tests/test_species_populations.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,32 +450,32 @@ def test_adjustment_exceptions(self):
self.local_species_pop.adjust_continuously(time, self.cont_submodel_id, {self.species_ids[0]: -10})
with self.assertRaises(DynamicSpeciesPopulationError) as context:
self.local_species_pop.adjust_continuously(time + 2, self.cont_submodel_id, {self.species_ids[0]: 0})
self.assertIn(f"{time + 2}: adjust_continuously error(s):", str(context.exception))
self.assertIn("adjust_continuously error(s):", str(context.exception))
self.assertIn("negative population predicted", str(context.exception))

def test_temp_lsp_populations(self):
s_0 = self.species_ids[0]
time = 1
pop_s_0 = self.local_species_pop.read_one(time, s_0)
temp_pop_s_0 = 18
self.local_species_pop.set_temp_populations({s_0: temp_pop_s_0})
self.local_species_pop.set_temp_populations(time, {s_0: temp_pop_s_0})
self.assertEqual(self.local_species_pop.read_one(time, s_0), temp_pop_s_0)
self.local_species_pop.clear_temp_populations({s_0})
self.local_species_pop.clear_temp_populations(time, {s_0})
self.assertEqual(self.local_species_pop.read_one(time, s_0), pop_s_0)

wc_sim.species_populations.RUN_TIME_ERROR_CHECKING = True
with self.assertRaises(DynamicSpeciesPopulationError):
self.local_species_pop.set_temp_populations({'not a species id': temp_pop_s_0})
self.local_species_pop.set_temp_populations(time, {'not a species id': temp_pop_s_0})

with self.assertRaisesRegex(SpeciesPopulationError, 'cannot use negative population'):
self.local_species_pop.set_temp_populations({s_0: -4})
self.local_species_pop.set_temp_populations(time, {s_0: -4})

with self.assertRaises(DynamicSpeciesPopulationError):
self.local_species_pop.clear_temp_populations(['not a species id'])
self.local_species_pop.clear_temp_populations(time, ['not a species id'])

wc_sim.species_populations.RUN_TIME_ERROR_CHECKING = False
with self.assertRaises(KeyError):
self.local_species_pop.set_temp_populations({'not a species id': temp_pop_s_0})
self.local_species_pop.set_temp_populations(time, {'not a species id': temp_pop_s_0})

def test_concentrations_api(self):
self.assertFalse(self.local_species_pop.concentrations_api())
Expand Down Expand Up @@ -690,7 +690,8 @@ def test(self):
temp_pop = 123
temp_pops = dict(zip(species_ids, [temp_pop]*num_species))
self.assertEqual(self.test_lsp.temporary_mode, False)
with TempPopulationsLSP(self.test_lsp, temp_pops):
time = 0
with TempPopulationsLSP(time, self.test_lsp, temp_pops):
self.assertEqual(self.test_lsp.temporary_mode, True)
for i in range(num_species):
self.assertEqual(self.test_lsp.read_one(1, species_ids[i]), temp_pop)
Expand Down
20 changes: 12 additions & 8 deletions wc_sim/species_populations.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ def read_one(self, time, species_id):
:obj:`float`: the predicted population of `species_id` at simulation time `time`.
"""
species_id_in_set = {species_id}
self._check_species(None, species_id_in_set, check_early_accesses=False)
self._check_species(time, species_id_in_set, check_early_accesses=False)
dynamic_species_state = self._population[species_id]
if not dynamic_species_state.get_temp_population_value() is None:
return dynamic_species_state.get_temp_population_value()
Expand Down Expand Up @@ -867,20 +867,21 @@ def read_into_array(self, time, species, populations, round=True):
populations[idx] = self._population[species_id].get_population(time, round=round)
# todo: combine read() and read_into_array() into 1 method

def set_temp_populations(self, populations):
def set_temp_populations(self, time, populations):
""" Set temporary population values for multiple species
Used to solve ODE submodels
Args:
time (:obj:`float`): simulation time
populations (:obj:`dict` of :obj:`float`): map: species_id -> temporary_population_value
Raises:
:obj:`SpeciesPopulationError`: if any of the species_ids in `populations` are unknown,
or if any population value would become negative
"""
species_ids = set(populations)
self._check_species(None, species_ids, check_early_accesses=False)
self._check_species(time, species_ids, check_early_accesses=False)
errors = []
for species_id, population in populations.items():
if population < 0:
Expand All @@ -890,16 +891,17 @@ def set_temp_populations(self, populations):
for species_id, population in populations.items():
self._population[species_id].set_temp_population_value(population)

def clear_temp_populations(self, species_ids):
def clear_temp_populations(self, time, species_ids):
""" Clear temporary population values for multiple species
Used to solve ODE submodels
Args:
time (:obj:`float`): simulation time
species_ids (:obj:`iterator`): an iterator over some species ids
"""
species_ids = set(species_ids)
self._check_species(None, species_ids, check_early_accesses=False)
self._check_species(time, species_ids, check_early_accesses=False)
for species_id in species_ids:
self._population[species_id].clear_temp_population_value()

Expand Down Expand Up @@ -1238,16 +1240,18 @@ def __str__(self):
class TempPopulationsLSP(object):
""" A context manager for using temporary population values in a LocalSpeciesPopulation
"""
def __init__(self, local_species_population, temporary_populations):
def __init__(self, time, local_species_population, temporary_populations):
""" Set populations temporarily, as specified in `temporary_populations`
Args:
time (:obj:`float`): simulation time
local_species_population (:obj:`LocalSpeciesPopulation`): an existing `LocalSpeciesPopulation`
temporary_populations (:obj:`dict` of :obj:`float`): map: species_id -> temporary_population_value;
temporary populations for some species in `local_species_population`
"""
self.time = time
self.local_species_population = local_species_population
local_species_population.set_temp_populations(temporary_populations)
local_species_population.set_temp_populations(self.time, temporary_populations)
self.species_ids = set(temporary_populations)
self.local_species_population.temporary_mode = True

Expand All @@ -1257,7 +1261,7 @@ def __enter__(self):
def __exit__(self, type, value, traceback):
""" Clear the temporary population values
"""
self.local_species_population.clear_temp_populations(self.species_ids)
self.local_species_population.clear_temp_populations(self.time, self.species_ids)
self.local_species_population.temporary_mode = False


Expand Down
1 change: 0 additions & 1 deletion wc_sim/submodels/dfba.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from wc_sim import message_types
from wc_sim.config import core as config_core_multialgorithm
from wc_sim.multialgorithm_errors import DynamicMultialgorithmError, MultialgorithmError
from wc_sim.species_populations import TempPopulationsLSP
from wc_sim.submodels.dynamic_submodel import ContinuousTimeSubmodel


Expand Down
2 changes: 1 addition & 1 deletion wc_sim/submodels/odes.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def compute_population_change_rates(self, time, new_species_populations, populat
# Hindmarsh, Serban and Reynolds, User Documentation for cvode v5.0.0, 2019
self.non_negative_populations = np.maximum(self.zero_populations, new_species_populations)
temporary_populations = dict(zip(self.species_ids, self.non_negative_populations))
with TempPopulationsLSP(self.local_species_population, temporary_populations):
with TempPopulationsLSP(time, self.local_species_population, temporary_populations):

# flush expressions that depend on species and reactions modeled by this ODE submodel from cache
self.dynamic_model.continuous_submodel_flush_after_populations_change(self.id)
Expand Down

0 comments on commit 6b6a7aa

Please sign in to comment.