Skip to content

Commit

Permalink
Incorporate SimulationMetadata in wc simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
artgoldberg committed May 18, 2018
1 parent b06f3d2 commit 9008125
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 32 deletions.
2 changes: 1 addition & 1 deletion tests/core/test_sim_metadata.py
Expand Up @@ -36,7 +36,7 @@ def setUp(self):

ip_address = socket.gethostbyname(socket.gethostname())
self.author = author = AuthorMetadata(name='Test user', email='test@test.com',
organization='Test organization', ip_address=ip_address)
username='Test username', organization='Test organization', ip_address=ip_address)

self.run = run = RunMetadata()
run.record_start()
Expand Down
18 changes: 13 additions & 5 deletions tests/multialgorithm/test_multialgorithm_main.py
Expand Up @@ -44,6 +44,11 @@ def test_parse_args(self):
for arg, value in args.__dict__.items():
self.assertEqual(getattr(original_args, arg), value)

args.dataframe_file = os.path.join(self.checkpoints_dir, 'dataframe_file_no_suffix')
original_args = copy(args)
SimController.process_and_validate_args(args)
self.assertEqual(args.dataframe_file, original_args.dataframe_file + '.h5')

# test error detection
errors = dict(
end_time=[-3, 0],
Expand All @@ -66,7 +71,8 @@ def test_parse_args(self):
checkpoints_dir=None,
fba_time_step=10,
)
with self.assertRaisesRegexp(ValueError, 'dataframe_file cannot be specified unless checkpoints_dir is provided'):
with self.assertRaisesRegexp(ValueError,
'dataframe_file cannot be specified unless checkpoints_dir is provided'):
SimController.process_and_validate_args(args)

def test_simulate(self):
Expand All @@ -77,14 +83,16 @@ def test_simulate(self):
'--checkpoint-period', '3',
'--checkpoints-dir', self.checkpoints_dir,
'--dataframe-file', os.path.join(self.checkpoints_dir, 'dataframe_file.h5'),
'--fba-time-step', '5.5',
'--fba-time-step', '5',
]
with __main__.App(argv=argv) as app:
with CaptureOutput() as capturer:
app.run()
match = re.match('^Saved (\d+) events to (.*?)$', capturer.get_text())
events = re.search('^Simulated (\d+) events', capturer.get_text())
checkpoints = re.search("Saved chcekpoints in '(.*?)'$", capturer.get_text())

num_events = int(match.group(1))
res_dirname = match.group(2)
num_events = int(events.group(1))
res_dirname = checkpoints.group(1)
# TODO(Arthur): stronger assertions
self.assertTrue(0 < num_events)
self.assertTrue(res_dirname.startswith(self.checkpoints_dir))
2 changes: 1 addition & 1 deletion tests/multialgorithm/test_multialgorithm_simulation.py
Expand Up @@ -261,8 +261,8 @@ def test_run_ssa_suite(self):
delta=0,
init_vol=1E-22)

# TODO(Arthur): check the random state in checkpoints
# TODO(Arthur): include metadata in checkpoints
# TODO(Arthur): check the random state in checkpoints
# TODO(Arthur): review the cement programs
# TODO(Arthur): put specie pop, random state, time, and metadata in the dataframe
# TODO(Arthur): graphs of a variety of models
Expand Down
8 changes: 5 additions & 3 deletions wc_sim/core/sim_metadata.py
Expand Up @@ -200,22 +200,24 @@ class AuthorMetadata(object):
Attributes:
name (:obj:`str`): authors' name
email (:obj:`str`): author's email address
username (:obj:`str`): authors' username
organization (:obj:`str`): author's organization
ip_address (:obj:`str`): author's ip address
"""

def __init__(self, name, email, organization, ip_address):
def __init__(self, name, email, username, organization, ip_address):
""" Construct a representation of the author of a simulation run
Args:
name (:obj:`str`): authors' name
email (:obj:`str`): author's email address
username (:obj:`str`): authors' username
organization (:obj:`str`): author's organization
ip_address (:obj:`str`): author's ip address
"""

self.name = name
self.email = email
self.username = username
self.organization = organization
self.ip_address = ip_address

Expand All @@ -231,7 +233,7 @@ def __eq__(self, other):
if other.__class__ is not self.__class__:
return False

attrs = ['name', 'email', 'organization', 'ip_address']
attrs = ['name', 'email', 'username', 'organization', 'ip_address']
for attr in attrs:
if getattr(other, attr) != getattr(self, attr):
return False
Expand Down
84 changes: 64 additions & 20 deletions wc_sim/multialgorithm/__main__.py
Expand Up @@ -2,20 +2,24 @@
""" Command line program for WC simulation
:Author: Arthur Goldberg, Arthur.Goldberg@mssm.edu
:Author: Jonathan Karr <karr@mssm.edu>
:Date: 2018-04-18
:Copyright: 2018, Karr Lab
:License: MIT
"""

import argparse
import os
import getpass
import sys
import socket
import datetime
import warnings
import pandas

from .config.core import get_config
from cement.core.controller import CementBaseController, expose

from wc_sim.core.sim_metadata import SimulationMetadata, ModelMetadata, AuthorMetadata, RunMetadata
from wc_sim.sim_config import SimulationConfig
from wc_sim.multialgorithm.multialgorithm_simulation import MultialgorithmSimulation
from wc_sim.multialgorithm.multialgorithm_errors import MultialgorithmError
from wc_lang.io import Reader
Expand All @@ -26,6 +30,7 @@
warnings.filterwarnings('ignore', '.*setting concentration.*', )

# get config
from .config.core import get_config
config = get_config()['wc_sim']['multialgorithm']


Expand All @@ -42,13 +47,13 @@ class Meta:
(['end_time'], dict(
type=float,
help="End time for the simulation (sec)")),
(['--checkpoints-dir'], dict(
type=str,
help="Store simulation results; if provided, a timestamped sub-directory will hold results")),
(['--checkpoint-period'], dict(
type=float,
default=config['checkpoint_period'],
help="Checkpointing period (sec)")),
(['--checkpoints-dir'], dict(
type=str,
help="Store simulation results; if provided, a timestamped sub-directory will hold results")),
(['--dataframe-file'], dict(
type=str,
help="File for storing Pandas DataFrame of checkpoints; written in HDF5; requires checkpoints_dir")),
Expand All @@ -72,13 +77,12 @@ def process_and_validate_args(args):
args (:obj:`object`): parsed command line arguments
Raises:
:obj:`ValueError`: if any fo the command line arguments are invalid
:obj:`ValueError`: if any of the command line arguments are invalid
"""

# process dataframe_file
if args.dataframe_file:
if not args.dataframe_file.endswith('.h5'):
args.dataframe_file = args.dataframe_file + '.h5'
if args.dataframe_file and not args.dataframe_file.endswith('.h5'):
args.dataframe_file = args.dataframe_file + '.h5'

# validate args
if args.end_time <= 0:
Expand All @@ -95,6 +99,39 @@ def process_and_validate_args(args):
if args.dataframe_file and not args.checkpoints_dir:
raise ValueError("dataframe_file cannot be specified unless checkpoints_dir is provided")

@staticmethod
def create_metadata(args):
""" Initialize metadata for this simulation run
Args:
args (:obj:`object`): parsed command line arguments
"""
model = ModelMetadata.create_from_repository()

# author metadata
# TODO: collect more comprehensive and specific author information
ip_address = socket.gethostbyname(socket.gethostname())
try:
username = getpass.getuser() + '(username)'
except:
username = 'Unknown username'
author = AuthorMetadata(name='Unknown name', email='Unknown email', username=username,
organization='Unknown organization', ip_address=ip_address)

# simulation config metadata
time_step = None
if args.fba_time_step:
time_step = args.fba_time_step
simulation_config = SimulationConfig(time_max=args.end_time, time_step=time_step)

# run metadata
run = RunMetadata()
run.record_start()
run.record_ip_address()

simulation_metadata = SimulationMetadata(model, simulation_config, run, author)
return simulation_metadata

@staticmethod
def simulate(args):
""" Run multialgorithmic simulation of a wc_lang model
Expand All @@ -103,7 +140,7 @@ def simulate(args):
args (:obj:`object`): parsed command line arguments
Raises:
:obj:`MultialgorithmError`: if a model cannot be read from the model file, or ...
:obj:`MultialgorithmError`: if a model cannot be read from the model file
"""
# read model
model_file = os.path.abspath(os.path.expanduser(args.model_file))
Expand All @@ -116,34 +153,41 @@ def simulate(args):
CheckModel(model).run()

# create results directory
results_sup_dir = os.path.abspath(os.path.expanduser(args.checkpoints_dir))
res_dirname = os.path.join(results_sup_dir, datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S'))
if not os.path.isdir(res_dirname):
os.makedirs(res_dirname)
res_dirname = None
if args.checkpoints_dir:
results_sup_dir = os.path.abspath(os.path.expanduser(args.checkpoints_dir))
res_dirname = os.path.join(results_sup_dir, datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S'))
if not os.path.isdir(res_dirname):
os.makedirs(res_dirname)

# create metadata
simulation_metadata = SimController.create_metadata(args)

# create a multi-algorithmic simulator
simulation_args = dict(
checkpoint_dir=res_dirname,
checkpoint_period=args.checkpoint_period,
# TODO(Arthur): provide metadata
metadata={},
metadata=simulation_metadata
)

# run simulation
multialgorithm_simulation = MultialgorithmSimulation(model, simulation_args)
# run simulation
multialgorithm_simulation = MultialgorithmSimulation(model, simulation_args)
simulation_engine, dynamic_model = multialgorithm_simulation.build_simulation()
simulation_engine.initialize()
simulation_engine.initialize()

# run simulation
num_events = simulation_engine.simulate(args.end_time)
simulation_metadata.run.record_end()

if args.dataframe_file:
pred_species_pops = MultialgorithmCheckpoint.convert_checkpoints(res_dirname)
store = pandas.HDFStore(args.dataframe_file)
store['dataframe'] = pred_species_pops
store.close()

print('Saved {} events to {}'.format(num_events, res_dirname))
print('Simulated {} events'.format(num_events))
if args.checkpoints_dir:
print("Saved chcekpoints in '{}'".format(res_dirname))


handlers = [
Expand Down
3 changes: 2 additions & 1 deletion wc_sim/multialgorithm/multialgorithm_checkpointing.py
Expand Up @@ -10,6 +10,7 @@

from wc_sim.log.checkpoint import Checkpoint
from wc_sim.core.simulation_checkpoint_object import CheckpointSimulationObject, AccessStateObjectInterface
from wc_sim.core.sim_metadata import SimulationMetadata
from wc_sim.multialgorithm.submodels.ssa import SSASubmodel


Expand Down Expand Up @@ -98,7 +99,7 @@ def __init__(self, name, checkpoint_period, checkpoint_dir, metadata, local_spec
name (:obj:`str`): name
checkpoint_period (:obj:`float`): checkpoint period
checkpoint_dir (:obj:`str`): checkpoint directory
metadata (:obj:``): metadata
metadata (:obj:`SimulationMetadata`): metadata
local_species_population (:obj:`LocalSpeciesPopulation`): the `LocalSpeciesPopulation`
dynamic_model (:obj:`DynamicModel`): the `DynamicModel`
multialgorithm_simulation (:obj:`MultialgorithmSimulation`): the `MultialgorithmSimulation`
Expand Down
3 changes: 2 additions & 1 deletion wc_sim/sim_config.py
Expand Up @@ -76,7 +76,8 @@ def __init__(self, time_init=0, time_max=3600, time_step=1, changes=None, pertur
raise SimulationConfigError('time_step must be positive')

if (time_max - time_init) / time_step % 1 != 0:
raise SimulationConfigError('(time_max - time_init) must be a multiple of time_step')
raise SimulationConfigError('(time_max - time_init) ({} - {}) must be a multiple of time_step ({})'.format(
time_max, time_init, time_step))

# random_seed
if random_seed is not None:
Expand Down

0 comments on commit 9008125

Please sign in to comment.