Skip to content

Commit

Permalink
Add simulation.run function for running models across years.
Browse files Browse the repository at this point in the history
  • Loading branch information
jiffyclub committed Jul 15, 2014
1 parent 432d2d9 commit 1ee790e
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 5 deletions.
39 changes: 34 additions & 5 deletions urbansim/sim/simulation.py
@@ -1,3 +1,5 @@
from __future__ import print_function

import inspect
from collections import Callable

Expand Down Expand Up @@ -106,7 +108,7 @@ class _TableFuncWrapper(object):
def __init__(self, name, func):
self.name = name
self._func = func
self._arg_list = inspect.getargspec(func).args
self._arg_list = set(inspect.getargspec(func).args)
self._columns = []

@property
Expand Down Expand Up @@ -157,7 +159,7 @@ def __init__(self, table_name, column_name, func):
self.table_name = table_name
self.name = column_name
self._func = func
self._arg_list = inspect.getargspec(func).args
self._arg_list = set(inspect.getargspec(func).args)

def __call__(self):
kwargs = {t: get_table(t) for t in self._arg_list}
Expand Down Expand Up @@ -202,10 +204,12 @@ class _ModelFuncWrapper(object):
def __init__(self, model_name, func):
self.name = model_name
self._func = func
self._arg_list = inspect.getargspec(func).args
self._arg_list = set(inspect.getargspec(func).args)

def __call__(self):
kwargs = {t: get_table(t) for t in self._arg_list}
def __call__(self, year=None):
kwargs = {t: get_table(t) for t in self._arg_list if t != 'year'}
if 'year' in self._arg_list:
kwargs['year'] = year
return self._func(**kwargs)


Expand Down Expand Up @@ -355,6 +359,10 @@ def add_model(model_name, func):
"""
Add a model function to the simulation.
Model argument names are used for injecting known tables of the same name.
The argument name "year" may be used to have the current simulation
year injected.
Parameters
----------
model_name : str
Expand Down Expand Up @@ -392,3 +400,24 @@ def get_model(model_name):
return _MODELS[model_name]
else:
raise KeyError('no model named {}'.format(model_name))


def run(models, years=None):
"""
Run models in series, optionally repeatedly over some years.
Parameters
----------
models : list of str
List of models to run identified by their name.
"""
years = years or [None]

for year in years:
if year:
print('Running year {}'.format(year))
for model_name in models:
print('Running model {}'.format(model_name))
model = get_model(model_name)
model(year=year)
39 changes: 39 additions & 0 deletions urbansim/sim/tests/test_simulation.py
Expand Up @@ -3,6 +3,7 @@
from pandas.util import testing as pdt

from .. import simulation as sim
from ...utils.testing import assert_frames_equal


@pytest.fixture
Expand Down Expand Up @@ -127,3 +128,41 @@ def test_model(test_table):
{'a': [5, 7, 9],
'b': [4, 5, 6]},
index=['x', 'y', 'z']))


def test_model_run(df, clear_sim):
sim.add_table('test_table', df)

@sim.table('table_func')
def table_func(test_table):
tt = test_table.to_frame()
tt['c'] = [7, 8, 9]
return tt

@sim.column('table_func', 'new_col')
def new_col(test_table, table_func):
tt = test_table.to_frame()
tf = table_func.to_frame(columns=['c'])
return tt['a'] + tt['b'] + tf['c']

@sim.model('test_model1')
def test_model1(year, test_table, table_func):
tf = table_func.to_frame(columns=['new_col'])
test_table[year] = tf['new_col'] + year

@sim.model('test_model2')
def test_model2(test_table):
tt = test_table.to_frame()
test_table['a'] = tt['a'] ** 2

sim.run(models=['test_model1', 'test_model2'], years=[2000, 3000])

test_table = sim.get_table('test_table')
assert_frames_equal(
test_table.to_frame(),
pd.DataFrame(
{'a': [1, 16, 81],
'b': [4, 5, 6],
2000: [2012, 2015, 2018],
3000: [3012, 3017, 3024]},
index=['x', 'y', 'z']))

0 comments on commit 1ee790e

Please sign in to comment.