Skip to content

Commit

Permalink
log simulation results to the specified directory rather than a subdi…
Browse files Browse the repository at this point in the history
…rectory whose name is a timestamp; issue #48; also fix excessive indentation
  • Loading branch information
artgoldberg committed Nov 3, 2019
1 parent 1fa797f commit 2319580
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 64 deletions.
3 changes: 2 additions & 1 deletion examples/simulation_run.py
Expand Up @@ -8,6 +8,7 @@

import os
import matplotlib.pyplot as plt
import tempfile

# import simulation and run results
from wc_sim.simulation import Simulation
Expand All @@ -17,7 +18,7 @@
# use a toy model
model_filename = os.path.join(os.path.dirname(__file__), '../tests/fixtures',
'2_species_1_reaction.xlsx')
results_dir = os.path.expanduser('~/tmp/checkpoints_dir')
results_dir = tempfile.mkdtemp(dir=os.path.join(os.path.expanduser('~/tmp/checkpoints_dir')))

# create and run simulation
simulation = Simulation(model_filename)
Expand Down
51 changes: 19 additions & 32 deletions tests/test_simulation.py
Expand Up @@ -76,7 +76,8 @@ def test_simulate(self):
end_time = 30
with CaptureOutput(relay=False):
num_events, results_dir = Simulation(TOY_MODEL_FILENAME).run(end_time=end_time,
results_dir=self.results_dir, checkpoint_period=10)
results_dir=self.results_dir,
checkpoint_period=10)

# check time, and simulation config in checkpoints
for time in Checkpoint.list_checkpoints(results_dir):
Expand All @@ -93,7 +94,8 @@ def test_reseed(self):
tmp_results_dir = tempfile.mkdtemp()
with CaptureOutput(relay=False):
num_events, results_dir = Simulation(TOY_MODEL_FILENAME).run(end_time=20,
results_dir=tmp_results_dir, checkpoint_period=5, seed=seed)
results_dir=tmp_results_dir,
checkpoint_period=5, seed=seed)
results[seed] = {}
results[seed]['num_events'] = num_events
run_results[seed] = RunResults(results_dir)
Expand All @@ -109,7 +111,8 @@ def test_reseed(self):
tmp_results_dir = tempfile.mkdtemp()
with CaptureOutput(relay=False):
num_events, results_dir = Simulation(TOY_MODEL_FILENAME).run(end_time=20,
results_dir=tmp_results_dir, checkpoint_period=5, seed=seed)
results_dir=tmp_results_dir,
checkpoint_period=5, seed=seed)
results[rep] = {}
results[rep]['num_events'] = num_events
run_results[rep] = RunResults(results_dir)
Expand Down Expand Up @@ -160,43 +163,27 @@ def test_create_metadata_2(self):
self.assertEqual(simulation_metadata.simulation.time_step, 1)

def test_ckpt_dir_processing_1(self):
# checkpoints_dir does not exist
# checkpoints_dir gets created because it does not exist
self.args['results_dir'] = os.path.join(self.results_dir, 'no_such_dir', 'no_such_sub_dir')
self.simulation.process_and_validate_args(self.args)
self.assertTrue(os.path.isdir(self.args['results_dir']))

def test_ckpt_dir_processing_2(self):
# checkpoints_dir exists, and is empty
root_dir = self.args['results_dir']
self.simulation.process_and_validate_args(self.args)
# process_and_validate_args creates 1 timestamped sub-dir
self.assertEqual(len(os.listdir(root_dir)), 1)

def test_ckpt_dir_processing_3(self):
# checkpoints_dir is a file
self.args['results_dir'] = os.path.join(self.args['results_dir'], 'new_file')
try:
open(self.args['results_dir'], 'x')
with self.assertRaises(MultialgorithmError):
self.simulation.process_and_validate_args(self.args)
except FileExistsError:
path = os.path.join(self.args['results_dir'], 'new_file')
self.args['results_dir'] = path
with open(path, 'w'):
pass
with self.assertRaises(MultialgorithmError):
self.simulation.process_and_validate_args(self.args)

def test_ckpt_dir_processing_4(self):
# timestamped sub-directory of checkpoints-dir already exists
root_dir = self.args['results_dir']
self.simulation.process_and_validate_args(self.args)
# given the chance, albeit small, that the second has advanced and
# a different timestamped sub-directory is made, try repeatedly to create the error
# the for loop takes about 0.01 sec
raised = False
for i in range(10):
self.args['results_dir'] = root_dir
try:
self.simulation.process_and_validate_args(self.args)
except:
raised = True
self.assertTrue(raised)
def test_ckpt_dir_processing_3(self):
# checkpoints_dir is not empty
path = os.path.join(self.args['results_dir'], 'new_file')
with open(path, 'w'):
pass
with self.assertRaises(MultialgorithmError):
self.simulation.process_and_validate_args(self.args)

def test_process_and_validate_args1(self):
original_args = copy(self.args)
Expand Down
4 changes: 2 additions & 2 deletions wc_sim/multialgorithm_simulation.py
Expand Up @@ -98,8 +98,8 @@ class MultialgorithmSimulation(object):
Attributes:
model (:obj:`Model`): a model description
args (:obj:`dict`): parameters for the simulation; if `results_dir` is provided, then also
must include checkpoint_period
args (:obj:`dict`): parameters for the simulation; if `results_dir` is an entry in `args`,
then `checkpoint_period` must also be included
simulation (:obj:`SimulationEngine`): the initialized simulation
checkpointing_sim_obj (:obj:`MultialgorithmicCheckpointingSimObj`): the checkpointing object;
`None` if absent
Expand Down
48 changes: 20 additions & 28 deletions wc_sim/simulation.py
Expand Up @@ -138,25 +138,19 @@ def process_and_validate_args(self, args):
if 'results_dir' in args:
results_sup_dir = os.path.abspath(os.path.expanduser(args['results_dir']))

# if results_sup_dir is a file, raise error
if os.path.isfile(results_sup_dir):
raise MultialgorithmError("results_dir ({}) is a file, not a dir".format(results_sup_dir))
if os.path.exists(results_sup_dir):
# raise error if results_sup_dir exists and is not a dir
if not os.path.isdir(results_sup_dir):
raise MultialgorithmError(f"results_dir ({results_sup_dir}) is not a dir")

# raise error if results_sup_dir is not empty
if os.listdir(results_sup_dir):
raise MultialgorithmError(f"results_dir ({results_sup_dir}) is not empty")

# if results_sup_dir does not exist, make it
if not os.path.exists(results_sup_dir):
os.makedirs(results_sup_dir)

# make a time-stamped sub-dir for this run
time_stamped_sub_dir = os.path.join(results_sup_dir, datetime.datetime.now().strftime(
'%Y-%m-%d-%H-%M-%S'))
if os.path.exists(time_stamped_sub_dir):
raise MultialgorithmError("timestamped sub-directory of results_dir ({}) already exists".format(
time_stamped_sub_dir))
else:
os.makedirs(time_stamped_sub_dir)
# update results_dir
args['results_dir'] = time_stamped_sub_dir

# validate args
if 'end_time' not in args:
raise MultialgorithmError("Simulation end time, end_time, must be provided")
Expand All @@ -166,8 +160,9 @@ def process_and_validate_args(self, args):

if 'checkpoint_period' in args:
if args['checkpoint_period'] <= 0 or args['end_time'] < args['checkpoint_period']:
raise MultialgorithmError("Checkpointing period ({}) must be positive and less than or equal to end time".format(
args['checkpoint_period']))
raise MultialgorithmError("Checkpointing period ({}) must be positive and "
"less than or equal to end time".format(
args['checkpoint_period']))

if args['end_time'] / args['checkpoint_period'] % 1 != 0:
raise MultialgorithmError('end_time ({}) must be a multiple of checkpoint_period ({})'.format(
Expand Down Expand Up @@ -211,16 +206,13 @@ def run(self, end_time, results_dir=None, checkpoint_period=None, time_step=1, s
simulation_args['checkpoint_period'] = checkpoint_period

self.process_and_validate_args(simulation_args)
timestamped_results_dir = None
if results_dir:
timestamped_results_dir = simulation_args['results_dir']

multialgorithm_simulation = MultialgorithmSimulation(self.model, simulation_args)
self.simulation_engine, self.dynamic_model = multialgorithm_simulation.build_simulation()
self.simulation_engine.initialize()

if timestamped_results_dir:
SimulationMetadata.write_metadata(self.simulation_metadata, timestamped_results_dir)
if results_dir:
SimulationMetadata.write_metadata(self.simulation_metadata, results_dir)

# run simulation
try:
Expand All @@ -234,15 +226,15 @@ def run(self, end_time, results_dir=None, checkpoint_period=None, time_step=1, s

self.simulation_metadata.run.record_end()
# update metadata in file
if timestamped_results_dir:
SimulationMetadata.write_metadata(self.simulation_metadata, timestamped_results_dir)
if results_dir:
SimulationMetadata.write_metadata(self.simulation_metadata, results_dir)

print('Simulated {} events'.format(num_events))
if timestamped_results_dir:
# summarize results in an HDF5 file in timestamped_results_dir
RunResults(timestamped_results_dir)
print("Saved checkpoints and run results in '{}'".format(timestamped_results_dir))
return (num_events, timestamped_results_dir)
if results_dir:
# summarize results in an HDF5 file in results_dir
RunResults(results_dir)
print("Saved checkpoints and run results in '{}'".format(results_dir))
return (num_events, results_dir)
else:
return (num_events, None)

Expand Down
8 changes: 7 additions & 1 deletion wc_sim/testing/utils.py
Expand Up @@ -8,6 +8,7 @@

from collections import defaultdict
import numpy as np
import os

from wc_lang import Model
from wc_lang.io import Reader
Expand Down Expand Up @@ -234,7 +235,12 @@ def define_trajectory_classes(model):


def verify_closed_form_model(test_case, model_filename, results_dir):
# alternatively, just load the SpeciesTrajectory & AggregateTrajectory worksheets into pandas
# empty results_dir
for file in os.listdir(results_dir):
file_path = os.path.join(results_dir, file)
if os.path.isfile(file_path):
os.unlink(file_path)

# read model while ignoring missing models, with std dev = 0
model = read_model_and_set_all_std_devs_to_0(model_filename)
# simulate model
Expand Down

0 comments on commit 2319580

Please sign in to comment.