diff --git a/.travis.yml b/.travis.yml index afc860a58f..6db9d33360 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,7 @@ install: cytoolz ipython-notebook jinja2 matplotlib numpy pandas pandana patsy pip pytables pytest pyyaml scipy statsmodels toolz - source activate test-environment -- pip install bottle prettytable simplejson zbox -- pip install https://github.com/synthicity/urbansim/archive/master.zip +- pip install bottle orca prettytable simplejson zbox - pip install openmatrix - pip install pytest-cov coveralls pep8 - pip install . diff --git a/activitysim/defaults/misc.py b/activitysim/defaults/misc.py index b4040adaf4..568a6c897a 100644 --- a/activitysim/defaults/misc.py +++ b/activitysim/defaults/misc.py @@ -1,37 +1,38 @@ -import urbansim.sim.simulation as sim -import warnings import os -import yaml -import pandas as pd +import warnings + import numpy as np +import orca +import pandas as pd +import yaml warnings.filterwarnings('ignore', category=pd.io.pytables.PerformanceWarning) pd.options.mode.chained_assignment = None -@sim.injectable() +@orca.injectable() def set_random_seed(): pass -@sim.injectable() +@orca.injectable() def configs_dir(): return '.' -@sim.injectable() +@orca.injectable() def data_dir(): return '.' -@sim.injectable() +@orca.injectable() def settings(configs_dir): with open(os.path.join(configs_dir, "configs", "settings.yaml")) as f: return yaml.load(f) -@sim.injectable(cache=True) +@orca.injectable(cache=True) def store(data_dir, settings): return pd.HDFStore(os.path.join(data_dir, "data", settings["store"]), mode='r') diff --git a/activitysim/defaults/models/auto_ownership.py b/activitysim/defaults/models/auto_ownership.py index 3f2242c961..4aed7801ba 100644 --- a/activitysim/defaults/models/auto_ownership.py +++ b/activitysim/defaults/models/auto_ownership.py @@ -1,5 +1,7 @@ import os -import urbansim.sim.simulation as sim + +import orca + from activitysim import activitysim as asim """ @@ -8,13 +10,13 @@ """ -@sim.injectable() +@orca.injectable() def auto_ownership_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "auto_ownership.csv") return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def auto_ownership_simulate(set_random_seed, households_merged, auto_ownership_spec): @@ -22,4 +24,4 @@ def auto_ownership_simulate(set_random_seed, households_merged, households_merged.to_frame(), auto_ownership_spec) print "Choices:\n", choices.value_counts() - sim.add_column("households", "auto_ownership", choices) + orca.add_column("households", "auto_ownership", choices) diff --git a/activitysim/defaults/models/cdap.py b/activitysim/defaults/models/cdap.py index d50f4ae544..397d1452a9 100644 --- a/activitysim/defaults/models/cdap.py +++ b/activitysim/defaults/models/cdap.py @@ -1,6 +1,8 @@ import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim + from activitysim import activitysim as asim from activitysim.cdap import cdap @@ -15,37 +17,37 @@ """ -@sim.injectable() +@orca.injectable() def cdap_1_person_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "cdap_1_person.csv") return asim.read_model_spec(f).fillna(0) -@sim.injectable() +@orca.injectable() def cdap_2_person_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "cdap_2_person.csv") return asim.read_model_spec(f).fillna(0) -@sim.injectable() +@orca.injectable() def cdap_3_person_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "cdap_3_person.csv") return asim.read_model_spec(f).fillna(0) -@sim.injectable() +@orca.injectable() def cdap_final_rules(configs_dir): f = os.path.join(configs_dir, 'configs', "cdap_final_rules.csv") return asim.read_model_spec(f).fillna(0) -@sim.injectable() +@orca.injectable() def cdap_all_people(configs_dir): f = os.path.join(configs_dir, 'configs', "cdap_all_people.csv") return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def cdap_simulate(set_random_seed, persons_merged, cdap_1_person_spec, cdap_2_person_spec, cdap_3_person_spec, cdap_final_rules, cdap_all_people): @@ -60,4 +62,4 @@ def cdap_simulate(set_random_seed, persons_merged, cdap_all_people) print "Choices:\n", choices.value_counts() - sim.add_column("persons", "cdap_activity", choices) + orca.add_column("persons", "cdap_activity", choices) diff --git a/activitysim/defaults/models/destination.py b/activitysim/defaults/models/destination.py index 2c14b8315a..3c160ab7a9 100644 --- a/activitysim/defaults/models/destination.py +++ b/activitysim/defaults/models/destination.py @@ -1,8 +1,10 @@ -import urbansim.sim.simulation as sim -from activitysim import activitysim as asim import os + +import orca import pandas as pd +from activitysim import activitysim as asim + """ Given the tour generation from the above, each tour needs to have a destination, so in this case tours are the choosers (with the associated @@ -10,13 +12,13 @@ """ -@sim.table() +@orca.table() def destination_choice_spec(configs_dir): f = os.path.join(configs_dir, 'configs', 'destination_choice.csv') return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def destination_choice(set_random_seed, non_mandatory_tours_merged, skims, @@ -64,4 +66,4 @@ def destination_choice(set_random_seed, print "Choices:\n", choices.describe() # every trip now has a destination which is the index from the # alternatives table - in this case it's the destination taz - sim.add_column("non_mandatory_tours", "destination", choices) + orca.add_column("non_mandatory_tours", "destination", choices) diff --git a/activitysim/defaults/models/mandatory_scheduling.py b/activitysim/defaults/models/mandatory_scheduling.py index b8072b036f..9d03fcdb97 100644 --- a/activitysim/defaults/models/mandatory_scheduling.py +++ b/activitysim/defaults/models/mandatory_scheduling.py @@ -1,6 +1,8 @@ import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim + from activitysim import activitysim as asim from .util.vectorize_tour_scheduling import vectorize_tour_scheduling @@ -10,7 +12,7 @@ """ -@sim.table() +@orca.table() def tdd_alts(configs_dir): # right now this file just contains the start and end hour f = os.path.join(configs_dir, "configs", @@ -20,19 +22,19 @@ def tdd_alts(configs_dir): # used to have duration in the actual alternative csv file, # but this is probably better as a computed column like this -@sim.column("tdd_alts") +@orca.column("tdd_alts") def duration(tdd_alts): return tdd_alts.end - tdd_alts.start -@sim.table() +@orca.table() def tdd_work_spec(configs_dir): f = os.path.join(configs_dir, 'configs', 'tour_departure_and_duration_work.csv') return asim.read_model_spec(f).fillna(0) -@sim.table() +@orca.table() def tdd_school_spec(configs_dir): f = os.path.join(configs_dir, 'configs', 'tour_departure_and_duration_school.csv') @@ -41,7 +43,7 @@ def tdd_school_spec(configs_dir): # I think it's easier to do this in one model so you can merge the two # resulting series together right away -@sim.model() +@orca.step() def mandatory_scheduling(set_random_seed, mandatory_tours_merged, tdd_alts, @@ -69,6 +71,5 @@ def mandatory_scheduling(set_random_seed, print "Choices:\n", choices.describe() - sim.add_column("mandatory_tours", - "tour_departure_and_duration", - choices) + orca.add_column( + "mandatory_tours", "tour_departure_and_duration", choices) diff --git a/activitysim/defaults/models/mandatory_tour_frequency.py b/activitysim/defaults/models/mandatory_tour_frequency.py index 0b34686438..2bcbe76add 100644 --- a/activitysim/defaults/models/mandatory_tour_frequency.py +++ b/activitysim/defaults/models/mandatory_tour_frequency.py @@ -1,6 +1,8 @@ import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim + from activitysim import activitysim as asim from .util.mandatory_tour_frequency import process_mandatory_tours @@ -10,13 +12,13 @@ """ -@sim.injectable() +@orca.injectable() def mandatory_tour_frequency_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "mandatory_tour_frequency.csv") return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def mandatory_tour_frequency(set_random_seed, persons_merged, mandatory_tour_frequency_spec): @@ -36,7 +38,7 @@ def mandatory_tour_frequency(set_random_seed, index=choices.index).reindex(persons_merged.local.index) print "Choices:\n", choices.value_counts() - sim.add_column("persons", "mandatory_tour_frequency", choices) + orca.add_column("persons", "mandatory_tour_frequency", choices) """ @@ -46,7 +48,7 @@ def mandatory_tour_frequency(set_random_seed, """ -@sim.table() +@orca.table() def mandatory_tours(persons): persons = persons.to_frame(columns=["mandatory_tour_frequency", "is_worker"]) @@ -55,7 +57,7 @@ def mandatory_tours(persons): # broadcast mandatory_tours on to persons using the person_id foreign key -sim.broadcast('persons', 'mandatory_tours', - cast_index=True, onto_on='person_id') -sim.broadcast('persons_merged', 'mandatory_tours', - cast_index=True, onto_on='person_id') +orca.broadcast('persons', 'mandatory_tours', + cast_index=True, onto_on='person_id') +orca.broadcast('persons_merged', 'mandatory_tours', + cast_index=True, onto_on='person_id') diff --git a/activitysim/defaults/models/mode.py b/activitysim/defaults/models/mode.py index c891c23e1a..7555bf05c6 100644 --- a/activitysim/defaults/models/mode.py +++ b/activitysim/defaults/models/mode.py @@ -1,8 +1,10 @@ -import os import copy -import yaml +import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim +import yaml + from activitysim import activitysim as asim from activitysim import skim as askim @@ -12,7 +14,7 @@ """ -@sim.injectable() +@orca.injectable() def mode_choice_settings(configs_dir): with open(os.path.join(configs_dir, "configs", "mode_choice.yaml")) as f: return yaml.load(f) @@ -45,7 +47,7 @@ def evaluate_expression_list(expressions, locals_d): return pd.Series(d) -@sim.injectable() +@orca.injectable() def mode_choice_coefficients(mode_choice_settings): # coefficients comes as a list of dicts and needs to be tuples coeffs = [x.items()[0] for x in mode_choice_settings['COEFFICIENTS']] @@ -54,7 +56,7 @@ def mode_choice_coefficients(mode_choice_settings): return evaluate_expression_list(expressions, locals_d=constants) -@sim.injectable() +@orca.injectable() def mode_choice_spec(configs_dir, mode_choice_coefficients): f = os.path.join(configs_dir, 'configs', "mode_choice_work.csv") df = asim.read_model_spec(f) @@ -67,7 +69,7 @@ def get_segment_and_unstack(spec, segment): return spec[segment].unstack().fillna(0) -@sim.model() +@orca.step() def mode_choice_simulate(tours_merged, mode_choice_spec, mode_choice_settings, @@ -100,4 +102,4 @@ def mode_choice_simulate(tours_merged, locals_d=locals_d) print "Choices:\n", choices.value_counts() - sim.add_column("tours", "mode", choices) + orca.add_column("tours", "mode", choices) diff --git a/activitysim/defaults/models/non_mandatory_scheduling.py b/activitysim/defaults/models/non_mandatory_scheduling.py index 8d94e4f0bb..198049aaa1 100644 --- a/activitysim/defaults/models/non_mandatory_scheduling.py +++ b/activitysim/defaults/models/non_mandatory_scheduling.py @@ -1,6 +1,8 @@ import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim + from activitysim import activitysim as asim from .util.vectorize_tour_scheduling import vectorize_tour_scheduling @@ -11,14 +13,14 @@ """ -@sim.table() +@orca.table() def tdd_non_mandatory_spec(configs_dir): f = os.path.join(configs_dir, 'configs', 'tour_departure_and_duration_nonmandatory.csv') return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def non_mandatory_scheduling(set_random_seed, non_mandatory_tours_merged, tdd_alts, @@ -35,6 +37,5 @@ def non_mandatory_scheduling(set_random_seed, print "Choices:\n", choices.describe() - sim.add_column("non_mandatory_tours", - "tour_departure_and_duration", - choices) + orca.add_column( + "non_mandatory_tours", "tour_departure_and_duration", choices) diff --git a/activitysim/defaults/models/non_mandatory_tour_frequency.py b/activitysim/defaults/models/non_mandatory_tour_frequency.py index 75177e964d..b4f483af6f 100644 --- a/activitysim/defaults/models/non_mandatory_tour_frequency.py +++ b/activitysim/defaults/models/non_mandatory_tour_frequency.py @@ -1,9 +1,11 @@ import os -import pandas as pd + import numpy as np -import urbansim.sim.simulation as sim -import urbansim.utils.misc as usim_misc +import orca +import pandas as pd + from activitysim import activitysim as asim +from activitysim.util import reindex from .util.non_mandatory_tour_frequency import process_non_mandatory_tours @@ -15,25 +17,25 @@ """ -@sim.injectable() +@orca.injectable() def non_mandatory_tour_frequency_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "non_mandatory_tour_frequency.csv") return asim.read_model_spec(f).fillna(0) -@sim.table() +@orca.table() def non_mandatory_tour_frequency_alts(configs_dir): f = os.path.join(configs_dir, "configs", "non_mandatory_tour_frequency_alternatives.csv") return pd.read_csv(f) -@sim.column("non_mandatory_tour_frequency_alts") +@orca.column("non_mandatory_tour_frequency_alts") def tot_tours(non_mandatory_tour_frequency_alts): return non_mandatory_tour_frequency_alts.local.sum(axis=1) -@sim.model() +@orca.step() def non_mandatory_tour_frequency(set_random_seed, persons_merged, non_mandatory_tour_frequency_alts, @@ -65,7 +67,7 @@ def non_mandatory_tour_frequency(set_random_seed, print "Choices:\n", choices.value_counts() - sim.add_column("persons", "non_mandatory_tour_frequency", choices) + orca.add_column("persons", "non_mandatory_tour_frequency", choices) """ @@ -76,7 +78,7 @@ def non_mandatory_tour_frequency(set_random_seed, """ -@sim.table() +@orca.table() def non_mandatory_tours(persons, non_mandatory_tour_frequency_alts): @@ -95,11 +97,11 @@ def non_mandatory_tours(persons, """ -@sim.column("non_mandatory_tours") +@orca.column("non_mandatory_tours") def destination_in_cbd(non_mandatory_tours, land_use, settings): # protection until filled in by destination choice model if "destination" not in non_mandatory_tours.columns: return pd.Series(False, index=non_mandatory_tours.index) - s = usim_misc.reindex(land_use.area_type, non_mandatory_tours.destination) + s = reindex(land_use.area_type, non_mandatory_tours.destination) return s < settings['cbd_threshold'] diff --git a/activitysim/defaults/models/school_location.py b/activitysim/defaults/models/school_location.py index e3c8bc4883..9b62e42208 100644 --- a/activitysim/defaults/models/school_location.py +++ b/activitysim/defaults/models/school_location.py @@ -1,6 +1,8 @@ import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim + from activitysim import activitysim as asim @@ -10,13 +12,13 @@ """ -@sim.table() +@orca.table() def school_location_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "school_location.csv") return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def school_location_simulate(set_random_seed, persons_merged, school_location_spec, @@ -58,4 +60,4 @@ def school_location_simulate(set_random_seed, choices = choices.reindex(persons_merged.index).fillna(-1) print "Describe of choices:\n", choices.describe() - sim.add_column("persons", "school_taz", choices) + orca.add_column("persons", "school_taz", choices) diff --git a/activitysim/defaults/models/workplace_location.py b/activitysim/defaults/models/workplace_location.py index d38ea5eecb..4aa398e5f4 100644 --- a/activitysim/defaults/models/workplace_location.py +++ b/activitysim/defaults/models/workplace_location.py @@ -1,5 +1,7 @@ import os -import urbansim.sim.simulation as sim + +import orca + from activitysim import activitysim as asim @@ -9,13 +11,13 @@ """ -@sim.injectable() +@orca.injectable() def workplace_location_spec(configs_dir): f = os.path.join(configs_dir, 'configs', "workplace_location.csv") return asim.read_model_spec(f).fillna(0) -@sim.model() +@orca.step() def workplace_location_simulate(set_random_seed, persons_merged, workplace_location_spec, @@ -44,4 +46,4 @@ def workplace_location_simulate(set_random_seed, choices = choices.reindex(persons_merged.index) print "Describe of choices:\n", choices.describe() - sim.add_column("persons", "workplace_taz", choices) + orca.add_column("persons", "workplace_taz", choices) diff --git a/activitysim/defaults/tables/accessibility.py b/activitysim/defaults/tables/accessibility.py index cc3353d793..08397fe48c 100644 --- a/activitysim/defaults/tables/accessibility.py +++ b/activitysim/defaults/tables/accessibility.py @@ -1,15 +1,15 @@ +import orca import pandas as pd -import urbansim.sim.simulation as sim -@sim.table(cache=True) +@orca.table(cache=True) def accessibility(store): df = store["skims/accessibility"] df.columns = [c.upper() for c in df.columns] return df -@sim.column("accessibility") +@orca.column("accessibility") def mode_choice_logsums(accessibility): # TODO a big todo here is to compute actual mode choice logsums from our # TODO upcoming mode choice model @@ -18,4 +18,4 @@ def mode_choice_logsums(accessibility): # this would be accessibility around the household location - be careful with # this one as accessibility at some other location can also matter -sim.broadcast('accessibility', 'households', cast_index=True, onto_on='TAZ') +orca.broadcast('accessibility', 'households', cast_index=True, onto_on='TAZ') diff --git a/activitysim/defaults/tables/households.py b/activitysim/defaults/tables/households.py index dac2b1fc64..20981e72af 100644 --- a/activitysim/defaults/tables/households.py +++ b/activitysim/defaults/tables/households.py @@ -1,11 +1,12 @@ -import pandas as pd import numpy as np -import urbansim.sim.simulation as sim -import urbansim.utils.misc as usim_misc +import orca +import pandas as pd + from activitysim import activitysim as asim +from activitysim.util import reindex -@sim.table(cache=True) +@orca.table(cache=True) def households(set_random_seed, store, settings): if "households_sample_size" in settings: @@ -16,34 +17,33 @@ def households(set_random_seed, store, settings): # this is a common merge so might as well define it once here and use it -@sim.table() +@orca.table() def households_merged(households, land_use, accessibility): - return sim.merge_tables(households.name, tables=[households, - land_use, - accessibility]) + return orca.merge_tables(households.name, tables=[ + households, land_use, accessibility]) -sim.broadcast('households', 'persons', cast_index=True, onto_on='household_id') +orca.broadcast('households', 'persons', cast_index=True, onto_on='household_id') -@sim.column("households") +@orca.column("households") def income_in_thousands(households): return households.income / 1000 -@sim.column("households") +@orca.column("households") def income_segment(households): return pd.cut(households.income_in_thousands, bins=[-np.inf, 30, 60, 100, np.inf], labels=[1, 2, 3, 4]) -@sim.column("households") +@orca.column("households") def non_workers(households, persons): return persons.household_id.value_counts() - households.workers -@sim.column("households") +@orca.column("households") def drivers(households, persons): # we assume that everyone 16 and older is a potential driver return persons.local.query("16 <= age").\ @@ -51,35 +51,35 @@ def drivers(households, persons): reindex(households.index).fillna(0) -@sim.column("households") +@orca.column("households") def num_young_children(households, persons): return persons.local.query("age <= 4").\ groupby("household_id").size().\ reindex(households.index).fillna(0) -@sim.column("households") +@orca.column("households") def num_children(households, persons): return persons.local.query("5 <= age <= 15").\ groupby("household_id").size().\ reindex(households.index).fillna(0) -@sim.column("households") +@orca.column("households") def num_adolescents(households, persons): return persons.local.query("16 <= age <= 17").\ groupby("household_id").size().\ reindex(households.index).fillna(0) -@sim.column("households") +@orca.column("households") def num_college_age(households, persons): return persons.local.query("18 <= age <= 24").\ groupby("household_id").size().\ reindex(households.index).fillna(0) -@sim.column("households") +@orca.column("households") def num_young_adults(households, persons): return persons.local.query("25 <= age <= 34").\ groupby("household_id").size().\ @@ -87,18 +87,18 @@ def num_young_adults(households, persons): # just a rename / alias -@sim.column("households") +@orca.column("households") def home_taz(households): return households.TAZ # map household type ids to strings -@sim.column("households") +@orca.column("households") def household_type(households, settings): return households.HHT.map(settings["household_type_map"]) -@sim.column("households") +@orca.column("households") def non_family(households): return households.household_type.isin(["nonfamily_male_alone", "nonfamily_male_notalone", @@ -107,52 +107,52 @@ def non_family(households): # can't just invert these unfortunately because there's a null household type -@sim.column("households") +@orca.column("households") def family(households): return households.household_type.isin(["family_married", "family_male", "family_female"]) -@sim.column("households") +@orca.column("households") def num_under16_not_at_school(persons, households): return persons.under16_not_at_school.groupby(persons.household_id).size().\ reindex(households.index).fillna(0) -@sim.column("households") +@orca.column("households") def auto_ownership(households): return pd.Series(0, households.index) -@sim.column('households') +@orca.column('households') def hhsize(households): return households.PERSONS -@sim.column('households') +@orca.column('households') def no_cars(households): return (households.auto_ownership == 0) -@sim.column('households') +@orca.column('households') def home_is_urban(households, land_use, settings): - s = usim_misc.reindex(land_use.area_type, households.home_taz) + s = reindex(land_use.area_type, households.home_taz) return s < settings['urban_threshold'] -@sim.column('households') +@orca.column('households') def home_is_rural(households, land_use, settings): - s = usim_misc.reindex(land_use.area_type, households.home_taz) + s = reindex(land_use.area_type, households.home_taz) return s > settings['rural_threshold'] -@sim.column('households') +@orca.column('households') def car_sufficiency(households, persons): return households.auto_ownership - persons.household_id.value_counts() -@sim.column('households') +@orca.column('households') def work_tour_auto_time_savings(households): # TODO fix this variable from auto ownership model return pd.Series(0, households.index) diff --git a/activitysim/defaults/tables/landuse.py b/activitysim/defaults/tables/landuse.py index d0bc974277..d5d4a4f446 100644 --- a/activitysim/defaults/tables/landuse.py +++ b/activitysim/defaults/tables/landuse.py @@ -1,51 +1,51 @@ -import urbansim.sim.simulation as sim +import orca -@sim.table(cache=True) +@orca.table(cache=True) def land_use(store): return store["land_use/taz_data"] -sim.broadcast('land_use', 'households', cast_index=True, onto_on='TAZ') +orca.broadcast('land_use', 'households', cast_index=True, onto_on='TAZ') -@sim.column("land_use") +@orca.column("land_use") def total_households(land_use): return land_use.local.TOTHH -@sim.column("land_use") +@orca.column("land_use") def total_employment(land_use): return land_use.local.TOTEMP -@sim.column("land_use") +@orca.column("land_use") def total_acres(land_use): return land_use.local.TOTACRE -@sim.column("land_use") +@orca.column("land_use") def county_id(land_use): return land_use.local.COUNTY -@sim.column("land_use") +@orca.column("land_use") def household_density(land_use): return land_use.total_households / land_use.total_acres -@sim.column("land_use") +@orca.column("land_use") def employment_density(land_use): return land_use.total_employment / land_use.total_acres -@sim.column("land_use") +@orca.column("land_use") def density_index(land_use): return (land_use.household_density * land_use.employment_density) / \ (land_use.household_density + land_use.employment_density) -@sim.column("land_use") +@orca.column("land_use") def county_name(land_use, settings): assert "county_map" in settings inv_map = {v: k for k, v in settings["county_map"].items()} diff --git a/activitysim/defaults/tables/persons.py b/activitysim/defaults/tables/persons.py index 7c547e5bc0..ea1116229c 100644 --- a/activitysim/defaults/tables/persons.py +++ b/activitysim/defaults/tables/persons.py @@ -1,11 +1,12 @@ -import pandas as pd import numpy as np +import orca +import pandas as pd + from activitysim.activitysim import other_than -import urbansim.sim.simulation as sim -import urbansim.utils.misc as usim_misc +from activitysim.util import reindex -@sim.table(cache=True) +@orca.table(cache=True) def persons(store, settings, households): df = store["persons"] @@ -17,30 +18,28 @@ def persons(store, settings, households): # another common merge for persons -@sim.table() +@orca.table() def persons_merged(persons, households, land_use, accessibility): - return sim.merge_tables(persons.name, tables=[persons, - households, - land_use, - accessibility]) + return orca.merge_tables(persons.name, tables=[ + persons, households, land_use, accessibility]) -@sim.column("persons") +@orca.column("persons") def age_16_to_19(persons): return persons.to_frame(["age"]).eval("16 <= age <= 19") -@sim.column("persons") +@orca.column("persons") def age_16_p(persons): return persons.to_frame(["age"]).eval("16 <= age") -@sim.column("persons") +@orca.column("persons") def adult(persons): return persons.to_frame(["age"]).eval("18 <= age") -@sim.column("persons") +@orca.column("persons") def cdap_activity(set_random_seed, persons): # return a default until it gets filled in by the model return pd.Series(np.random.randint(3, size=len(persons)), @@ -49,56 +48,56 @@ def cdap_activity(set_random_seed, persons): # FIXME - these are my "placeholder" for joint trip generation # number of joint shopping tours -@sim.column("persons") +@orca.column("persons") def num_shop_j(persons): return pd.Series(0, persons.index) # FIXME - these are my "placeholder" for joint trip generation # number of joint shopping tours -@sim.column("persons") +@orca.column("persons") def num_main_j(persons): return pd.Series(0, persons.index) # FIXME - these are my "placeholder" for joint trip generation # number of joint shopping tours -@sim.column("persons") +@orca.column("persons") def num_eat_j(persons): return pd.Series(0, persons.index) # FIXME - these are my "placeholder" for joint trip generation # number of joint shopping tours -@sim.column("persons") +@orca.column("persons") def num_visi_j(persons): return pd.Series(0, persons.index) # FIXME - these are my "placeholder" for joint trip generation # number of joint shopping tours -@sim.column("persons") +@orca.column("persons") def num_disc_j(persons): return pd.Series(0, persons.index) -@sim.column("persons") +@orca.column("persons") def num_joint_tours(persons): return persons.num_shop_j + persons.num_main_j + persons.num_eat_j +\ persons.num_visi_j + persons.num_disc_j -@sim.column("persons") +@orca.column("persons") def male(persons): return persons.sex == 1 -@sim.column("persons") +@orca.column("persons") def female(persons): return persons.sex == 1 -@sim.column("persons") +@orca.column("persons") def num_escort_tours(persons, non_mandatory_tours): if "non_mandatory_tour_frequency" not in persons.columns: return pd.Series(0, index=persons.index) @@ -108,7 +107,7 @@ def num_escort_tours(persons, non_mandatory_tours): .reindex(persons.index).fillna(0) -@sim.column("persons") +@orca.column("persons") def num_non_escort_tours(persons, non_mandatory_tours): if "non_mandatory_tour_frequency" not in persons.columns: return pd.Series(0, index=persons.index) @@ -119,7 +118,7 @@ def num_non_escort_tours(persons, non_mandatory_tours): # count the number of mandatory tours for each person -@sim.column("persons") +@orca.column("persons") def num_mand(persons): if "mandatory_tour_frequency" not in persons.columns: return pd.Series(0, index=persons.index) @@ -134,7 +133,7 @@ def num_mand(persons): return s.fillna(0) -@sim.column("persons") +@orca.column("persons") def work_and_school_and_worker(persons): if "mandatory_tour_frequency" not in persons.columns: return pd.Series(0, index=persons.index) @@ -145,7 +144,7 @@ def work_and_school_and_worker(persons): return s & persons.is_worker -@sim.column("persons") +@orca.column("persons") def work_and_school_and_student(persons): if "mandatory_tour_frequency" not in persons.columns: return pd.Series(0, index=persons.index) @@ -158,93 +157,92 @@ def work_and_school_and_student(persons): # FIXME now totally sure what this is but it's used in non mandatory tour # FIXME generation and probably has to do with remaining unscheduled time -@sim.column('persons') +@orca.column('persons') def max_window(persons): return pd.Series(0, persons.index) # convert employment categories to string descriptors -@sim.column("persons") +@orca.column("persons") def employed_cat(persons, settings): return persons.pemploy.map(settings["employment_map"]) # convert student categories to string descriptors -@sim.column("persons") +@orca.column("persons") def student_cat(persons, settings): return persons.pstudent.map(settings["student_map"]) # convert person type categories to string descriptors -@sim.column("persons") +@orca.column("persons") def ptype_cat(persons, settings): return persons.ptype.map(settings["person_type_map"]) # borrowing these definitions from the original code -@sim.column("persons") +@orca.column("persons") def student_is_employed(persons): return (persons.ptype_cat.isin(['university', 'driving']) & persons.employed_cat.isin(['full', 'part'])) -@sim.column("persons") +@orca.column("persons") def nonstudent_to_school(persons): return (persons.ptype_cat.isin(['full', 'part', 'nonwork', 'retired']) & persons.student_cat.isin(['grade_or_high', 'college'])) -@sim.column("persons") +@orca.column("persons") def under16_not_at_school(persons): return (persons.ptype_cat.isin(["school", "preschool"]) & persons.cdap_activity.isin(["N", "H"])) -@sim.column("persons") +@orca.column("persons") def is_worker(persons): return persons.employed_cat.isin(['full', 'part']) -@sim.column("persons") +@orca.column("persons") def is_student(persons): return persons.student_cat.isin(['grade_or_high', 'college']) -@sim.column("persons") +@orca.column("persons") def is_gradeschool(persons, settings): return (persons.student_cat == "grade_or_high") & \ (persons.age <= settings['grade_school_max_age']) -@sim.column("persons") +@orca.column("persons") def is_highschool(persons, settings): return (persons.student_cat == "grade_or_high") & \ (persons.age > settings['grade_school_max_age']) -@sim.column("persons") +@orca.column("persons") def is_university(persons): return persons.student_cat == "university" -@sim.column("persons") +@orca.column("persons") def workplace_taz(persons): return pd.Series(1, persons.index) -@sim.column("persons") +@orca.column("persons") def home_taz(households, persons): - return usim_misc.reindex(households.home_taz, - persons.household_id) + return reindex(households.home_taz, persons.household_id) -@sim.column("persons") +@orca.column("persons") def school_taz(persons): return pd.Series(1, persons.index) # this use the distance skims to compute the raw distance to work from home -@sim.column("persons") +@orca.column("persons") def distance_to_work(persons, distance_skim): return pd.Series(distance_skim.get(persons.home_taz, persons.workplace_taz), @@ -252,7 +250,7 @@ def distance_to_work(persons, distance_skim): # same deal but to school -@sim.column("persons") +@orca.column("persons") def distance_to_school(persons, distance_skim): return pd.Series(distance_skim.get(persons.home_taz, persons.school_taz), @@ -261,7 +259,7 @@ def distance_to_school(persons, distance_skim): # similar but this adds the am peak travel time to the pm peak travel time in # the opposite direction (by car) -@sim.column("persons") +@orca.column("persons") def roundtrip_auto_time_to_work(persons, sovam_skim, sovpm_skim): return pd.Series(sovam_skim.get(persons.home_taz, persons.workplace_taz) + @@ -272,7 +270,7 @@ def roundtrip_auto_time_to_work(persons, sovam_skim, sovpm_skim): # this adds the am peak travel time to the md peak travel time in # the opposite direction (by car), assuming students leave school earlier -@sim.column("persons") +@orca.column("persons") def roundtrip_auto_time_to_school(persons, sovam_skim, sovmd_skim): return pd.Series(sovam_skim.get(persons.home_taz, persons.school_taz) + @@ -281,9 +279,9 @@ def roundtrip_auto_time_to_school(persons, sovam_skim, sovmd_skim): index=persons.index) -@sim.column('persons') +@orca.column('persons') def workplace_in_cbd(persons, land_use, settings): - s = usim_misc.reindex(land_use.area_type, persons.workplace_taz) + s = reindex(land_use.area_type, persons.workplace_taz) return s < settings['cbd_threshold'] @@ -299,51 +297,51 @@ def presence_of(ptype, persons, at_home=False): return other_than(persons.household_id, bools) -@sim.column('persons') +@orca.column('persons') def has_non_worker(persons): return presence_of("nonwork", persons) -@sim.column('persons') +@orca.column('persons') def has_retiree(persons): return presence_of("retired", persons) -@sim.column('persons') +@orca.column('persons') def has_preschool_kid(persons): return presence_of("preschool", persons) -@sim.column('persons') +@orca.column('persons') def has_preschool_kid_at_home(persons): return presence_of("preschool", persons, at_home=True) -@sim.column('persons') +@orca.column('persons') def has_driving_kid(persons): return presence_of("driving", persons) -@sim.column('persons') +@orca.column('persons') def has_school_kid(persons): return presence_of("school", persons) -@sim.column('persons') +@orca.column('persons') def has_school_kid_at_home(persons): return presence_of("school", persons, at_home=True) -@sim.column('persons') +@orca.column('persons') def has_full_time(persons): return presence_of("full", persons) -@sim.column('persons') +@orca.column('persons') def has_part_time(persons): return presence_of("part", persons) -@sim.column('persons') +@orca.column('persons') def has_university(persons): return presence_of("university", persons) diff --git a/activitysim/defaults/tables/size_terms.py b/activitysim/defaults/tables/size_terms.py index c19e77db16..521661d17c 100644 --- a/activitysim/defaults/tables/size_terms.py +++ b/activitysim/defaults/tables/size_terms.py @@ -1,6 +1,7 @@ import os + +import orca import pandas as pd -import urbansim.sim.simulation as sim def size_term(land_use, destination_choice_coeffs): @@ -37,14 +38,14 @@ def size_term(land_use, destination_choice_coeffs): return land_use[coeffs.index].dot(coeffs) -@sim.table() +@orca.table() def size_terms(configs_dir): f = os.path.join(configs_dir, 'configs', 'destination_choice_size_terms.csv') return pd.read_csv(f, index_col='segment') -@sim.table() +@orca.table() def destination_size_terms(land_use, size_terms): land_use = land_use.to_frame() size_terms = size_terms.to_frame() diff --git a/activitysim/defaults/tables/skims.py b/activitysim/defaults/tables/skims.py index c41344ed3e..1829cfcdb1 100644 --- a/activitysim/defaults/tables/skims.py +++ b/activitysim/defaults/tables/skims.py @@ -1,47 +1,49 @@ -import urbansim.sim.simulation as sim +import os + import openmatrix as omx +import orca + from activitysim import skim -import os """ Read in the omx files and create the skim objects """ -@sim.injectable() +@orca.injectable() def nonmotskm_omx(data_dir): return omx.openFile(os.path.join(data_dir, 'data', "nonmotskm.omx")) -@sim.injectable() +@orca.injectable() def nonmotskm_matrix(nonmotskm_omx): return nonmotskm_omx['DIST'] -@sim.injectable() +@orca.injectable() def distance_skim(nonmotskm_matrix): return skim.Skim(nonmotskm_matrix, offset=-1) -@sim.injectable() +@orca.injectable() def sovam_skim(nonmotskm_matrix): # FIXME use the right omx file return skim.Skim(nonmotskm_matrix, offset=-1) -@sim.injectable() +@orca.injectable() def sovmd_skim(nonmotskm_matrix): # FIXME use the right omx file return skim.Skim(nonmotskm_matrix, offset=-1) -@sim.injectable() +@orca.injectable() def sovpm_skim(nonmotskm_matrix): # FIXME use the right omx file return skim.Skim(nonmotskm_matrix, offset=-1) -@sim.injectable(cache=True) +@orca.injectable(cache=True) def skims(): skims = skim.Skims() # FIXME - this is reusing the same skim as all the different kinds of skims @@ -50,6 +52,6 @@ def skims(): "SOV_BTOLL", "SOVTOLL_BTOLL", "HOV2_BTOLL", "SOVTOLL_VTOLL"]: for period in ["AM", "MD", "PM"]: - skims[(typ, period)] = sim.get_injectable("distance_skim") - skims['DISTANCE'] = sim.get_injectable("distance_skim") + skims[(typ, period)] = orca.get_injectable("distance_skim") + skims['DISTANCE'] = orca.get_injectable("distance_skim") return skims diff --git a/activitysim/defaults/tables/tours.py b/activitysim/defaults/tables/tours.py index f0bbbc0ee9..d02323d782 100644 --- a/activitysim/defaults/tables/tours.py +++ b/activitysim/defaults/tables/tours.py @@ -1,8 +1,8 @@ +import orca import pandas as pd -import urbansim.sim.simulation as sim -@sim.table() +@orca.table() def tours(non_mandatory_tours, mandatory_tours, tdd_alts): tours = pd.concat([non_mandatory_tours.to_frame(), mandatory_tours.to_frame()], @@ -13,89 +13,89 @@ def tours(non_mandatory_tours, mandatory_tours, tdd_alts): return pd.concat([tours, chosen_tours], axis=1) -@sim.table() +@orca.table() def mandatory_tours_merged(mandatory_tours, persons_merged): - return sim.merge_tables(mandatory_tours.name, - [mandatory_tours, persons_merged]) + return orca.merge_tables(mandatory_tours.name, + [mandatory_tours, persons_merged]) -@sim.table() +@orca.table() def non_mandatory_tours_merged(non_mandatory_tours, persons_merged): tours = non_mandatory_tours - return sim.merge_tables(tours.name, tables=[tours, - persons_merged]) + return orca.merge_tables(tours.name, tables=[ + tours, persons_merged]) -@sim.table() +@orca.table() def tours_merged(tours, persons_merged): - return sim.merge_tables(tours.name, tables=[tours, - persons_merged]) + return orca.merge_tables(tours.name, tables=[ + tours, persons_merged]) # broadcast trips onto persons using the person_id -sim.broadcast('persons', 'non_mandatory_tours', - cast_index=True, onto_on='person_id') -sim.broadcast('persons_merged', 'non_mandatory_tours', - cast_index=True, onto_on='person_id') -sim.broadcast('persons_merged', 'tours', cast_index=True, onto_on='person_id') +orca.broadcast('persons', 'non_mandatory_tours', + cast_index=True, onto_on='person_id') +orca.broadcast('persons_merged', 'non_mandatory_tours', + cast_index=True, onto_on='person_id') +orca.broadcast('persons_merged', 'tours', cast_index=True, onto_on='person_id') -@sim.column("tours") +@orca.column("tours") def sov_available(tours): # FIXME return pd.Series(1, index=tours.index) -@sim.column("tours") +@orca.column("tours") def hov2_available(tours): # FIXME return pd.Series(1, index=tours.index) -@sim.column("tours") +@orca.column("tours") def sovtoll_available(tours): # FIXME return pd.Series(1, index=tours.index) -@sim.column("tours") +@orca.column("tours") def is_joint(tours): # FIXME return pd.Series(False, index=tours.index) -@sim.column("tours") +@orca.column("tours") def number_of_participants(tours): # FIXME return pd.Series(1, index=tours.index) -@sim.column("tours") +@orca.column("tours") def work_tour_is_drive(tours): # FIXME return pd.Series(0, index=tours.index) -@sim.column("tours") +@orca.column("tours") def terminal_time(tours): # FIXME return pd.Series(0, index=tours.index) -@sim.column("tours") +@orca.column("tours") def daily_parking_cost(tours): # FIXME - this is a computation based on the tour destination return pd.Series(0, index=tours.index) -@sim.column("tours") +@orca.column("tours") def out_period(tours, settings): return pd.cut(tours.end, settings['time_periods']['hours'], labels=settings['time_periods']['labels']) -@sim.column("tours") +@orca.column("tours") def in_period(tours, settings): return pd.cut(tours.start, settings['time_periods']['hours'], diff --git a/activitysim/defaults/test/test_defaults.py b/activitysim/defaults/test/test_defaults.py index def61cf92e..d888b8ad8f 100644 --- a/activitysim/defaults/test/test_defaults.py +++ b/activitysim/defaults/test/test_defaults.py @@ -2,16 +2,17 @@ # Copyright (C) 2014-2015 Synthicity, LLC # See full license in LICENSE.txt. - -import pytest import os + +import numpy as np +import orca import pandas as pd import pandas.util.testing as pdt -import numpy as np -import urbansim.sim.simulation as sim +import pytest +import yaml + from .. import __init__ from ..tables import size_terms -import yaml # set the max households for all tests (this is to limit memory use on travis) @@ -30,7 +31,7 @@ def fin(): return store -@sim.injectable(cache=False) +@orca.injectable(cache=False) def settings(configs_dir): with open(os.path.join(configs_dir, "configs", "settings.yaml")) as f: obj = yaml.load(f) @@ -61,33 +62,33 @@ def test_size_term(): def test_mini_run(store): - sim.add_injectable("configs_dir", - os.path.join(os.path.dirname(__file__))) + orca.add_injectable("configs_dir", + os.path.join(os.path.dirname(__file__))) - sim.add_injectable("store", store) + orca.add_injectable("store", store) - sim.add_injectable("nonmotskm_matrix", np.ones((1454, 1454))) - sim.add_injectable("set_random_seed", set_random_seed) + orca.add_injectable("nonmotskm_matrix", np.ones((1454, 1454))) + orca.add_injectable("set_random_seed", set_random_seed) - assert len(sim.get_table("households").index) == HOUSEHOLDS_SAMPLE_SIZE + assert len(orca.get_table("households").index) == HOUSEHOLDS_SAMPLE_SIZE # run the models in the expected order - sim.run(["workplace_location_simulate"]) - sim.run(["auto_ownership_simulate"]) + orca.run(["workplace_location_simulate"]) + orca.run(["auto_ownership_simulate"]) # this is a regression test so that we know if these numbers change - auto_choice = sim.get_table('households').get_column('auto_ownership') + auto_choice = orca.get_table('households').get_column('auto_ownership') pdt.assert_series_equal( auto_choice[[2306822, 652072, 651907]], pd.Series( [3, 1, 0], index=[2306822, 652072, 651907])) - sim.run(["cdap_simulate"]) + orca.run(["cdap_simulate"]) - sim.run(['mandatory_tour_frequency']) + orca.run(['mandatory_tour_frequency']) - mtf_choice = sim.get_table('persons').get_column( + mtf_choice = orca.get_table('persons').get_column( 'mandatory_tour_frequency') pdt.assert_series_equal( @@ -96,37 +97,37 @@ def test_mini_run(store): ['work_and_school', 'work2', 'school2'], index=[146642, 642922, 642921])) - sim.clear_cache() + orca.clear_cache() def test_full_run(store): - sim.add_injectable("configs_dir", - os.path.join(os.path.dirname(__file__), '..', '..', - '..', 'example')) + orca.add_injectable("configs_dir", + os.path.join(os.path.dirname(__file__), '..', '..', + '..', 'example')) - sim.add_injectable("store", store) + orca.add_injectable("store", store) - sim.add_injectable("nonmotskm_matrix", np.ones((1454, 1454))) - sim.add_injectable("set_random_seed", set_random_seed) + orca.add_injectable("nonmotskm_matrix", np.ones((1454, 1454))) + orca.add_injectable("set_random_seed", set_random_seed) # grab some of the tables - sim.get_table("land_use").to_frame().info() - sim.get_table("households").to_frame().info() - sim.get_table("persons").to_frame().info() + orca.get_table("land_use").to_frame().info() + orca.get_table("households").to_frame().info() + orca.get_table("persons").to_frame().info() - assert len(sim.get_table("households").index) == HOUSEHOLDS_SAMPLE_SIZE + assert len(orca.get_table("households").index) == HOUSEHOLDS_SAMPLE_SIZE # run the models in the expected order - sim.run(["workplace_location_simulate"]) - sim.run(["auto_ownership_simulate"]) - sim.run(["cdap_simulate"]) - sim.run(['mandatory_tour_frequency']) - sim.get_table("mandatory_tours").tour_type.value_counts() - sim.run(['non_mandatory_tour_frequency']) - sim.get_table("non_mandatory_tours").tour_type.value_counts() - sim.run(["destination_choice"]) - sim.run(["mandatory_scheduling"]) - sim.run(["non_mandatory_scheduling"]) - sim.run(["mode_choice_simulate"]) - - sim.clear_cache() + orca.run(["workplace_location_simulate"]) + orca.run(["auto_ownership_simulate"]) + orca.run(["cdap_simulate"]) + orca.run(['mandatory_tour_frequency']) + orca.get_table("mandatory_tours").tour_type.value_counts() + orca.run(['non_mandatory_tour_frequency']) + orca.get_table("non_mandatory_tours").tour_type.value_counts() + orca.run(["destination_choice"]) + orca.run(["mandatory_scheduling"]) + orca.run(["non_mandatory_scheduling"]) + orca.run(["mode_choice_simulate"]) + + orca.clear_cache() diff --git a/activitysim/util/__init__.py b/activitysim/util/__init__.py index fd8a0284a5..14da53f73c 100644 --- a/activitysim/util/__init__.py +++ b/activitysim/util/__init__.py @@ -1,3 +1,5 @@ # ActivitySim # Copyright (C) 2014-2015 Synthicity, LLC # See full license in LICENSE.txt. + +from .reindex import reindex diff --git a/activitysim/util/reindex.py b/activitysim/util/reindex.py new file mode 100644 index 0000000000..33f410fde9 --- /dev/null +++ b/activitysim/util/reindex.py @@ -0,0 +1,47 @@ +import pandas as pd + + +def reindex(series1, series2): + """ + This reindexes the first series by the second series. This is an extremely + common operation that does not appear to be in Pandas at this time. + If anyone knows of an easier way to do this in Pandas, please inform the + UrbanSim developers. + + The canonical example would be a parcel series which has an index which is + parcel_ids and a value which you want to fetch, let's say it's land_area. + Another dataset, let's say of buildings has a series which indicate the + parcel_ids that the buildings are located on, but which does not have + land_area. If you pass parcels.land_area as the first series and + buildings.parcel_id as the second series, this function returns a series + which is indexed by buildings and has land_area as values and can be + added to the buildings dataset. + + In short, this is a join on to a different table using a foreign key + stored in the current table, but with only one attribute rather than + for a full dataset. + + This is very similar to the pandas "loc" function or "reindex" function, + but neither of those functions return the series indexed on the current + table. In both of those cases, the series would be indexed on the foreign + table and would require a second step to change the index. + + Parameters + ---------- + series1, series2 : pandas.Series + + Returns + ------- + reindexed : pandas.Series + + """ + + # turns out the merge is much faster than the .loc below + df = pd.merge(series2.to_frame(name='left'), + series1.to_frame(name='right'), + left_on="left", + right_index=True, + how="left") + return df.right + + # return pd.Series(series1.loc[series2.values].values, index=series2.index) diff --git a/activitysim/util/test/test_reindex.py b/activitysim/util/test/test_reindex.py new file mode 100644 index 0000000000..6a46ef6821 --- /dev/null +++ b/activitysim/util/test/test_reindex.py @@ -0,0 +1,9 @@ +import pandas as pd + +from ..reindex import reindex + + +def test_reindex(): + s = pd.Series([.5, 1.0, 1.5], index=[2, 1, 3]) + s2 = pd.Series([1, 2, 3], index=['a', 'b', 'c']) + assert list(reindex(s, s2).values) == [1.0, .5, 1.5] diff --git a/activitysim/util/testing.py b/activitysim/util/testing.py index e782b7db02..6a0a7d48d6 100644 --- a/activitysim/util/testing.py +++ b/activitysim/util/testing.py @@ -3,7 +3,7 @@ # See full license in LICENSE.txt. """ -Utilities used in testing of UrbanSim. +Utilities used in testing of ActivitySim. """ import numpy.testing as npt diff --git a/setup.py b/setup.py index 2001d26ccd..30311a01e2 100644 --- a/setup.py +++ b/setup.py @@ -20,10 +20,10 @@ install_requires=[ 'numpy >= 1.8.0', 'openmatrix >= 0.2.2', + 'orca >= 1.1', 'pandas >= 0.13.1', 'tables >= 3.1.0', 'toolz >= 0.7', - 'urbansim >= 1.3', 'zbox >= 1.2' ] )