Skip to content

Commit e5f8e27

Browse files
committed
initial commit
1 parent 932d307 commit e5f8e27

File tree

193 files changed

+27437
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

193 files changed

+27437
-1
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/test/prototype_mtc_reference_pipeline.zip
2+
/test/prototype_mtc_reference_pipeline_sharrow.zip
3+
/test/.coverage
4+
.idea/**

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,17 @@
11
# activitysim-prototype-mtc
2-
The canonical prototype MTC model.
2+
3+
The primary ActivitySim example model.
4+
5+
The `prototype_mtc` example is based on (but has evolved away from) the
6+
[Bay Area Metro Travel Model One](https://github.com/BayAreaMetro/travel-model-one),
7+
also known as "TM1". TM1 has its roots in a wide array of analytical approaches,
8+
including discrete choice forms (multinomial and nested logit models), activity
9+
duration models, time-use models, models of individual micro-simulation with
10+
constraints, entropy-maximization models, etc. These tools are combined in the
11+
model design to realistically represent travel behavior, adequately replicate
12+
observed activity-travel patterns, and ensure model sensitivity to infrastructure
13+
and policies. The model is implemented in a micro-simulation framework. Microsimulation
14+
methods capture aggregate outcomes through the representation of the behavior of
15+
individual decision-makers.
16+
17+
See https://activitysim.github.io for more information.

configs/accessibility.csv

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
Description,Target,Expression
2+
#,,
3+
#,, auto peak
4+
#,,
5+
#,, assume peak occurs in AM for outbound and PM for inbound
6+
peak round trip distance,_auPkTime,"skim_od[('SOVTOLL_TIME', 'AM')] + skim_do[('SOVTOLL_TIME', 'PM')]"
7+
decay function,_decay, exp(_auPkTime * dispersion_parameter_automobile)
8+
auto peak retail,auPkRetail,df.RETEMPN * _decay
9+
auto peak total,auPkTotal,df.TOTEMP * _decay
10+
#,,
11+
#,, auto off-peak
12+
#,,
13+
#,, assume midday occurs entirely in the midday period
14+
off-peak round trip distance,_auOpTime,"skim_od[('SOVTOLL_TIME', 'MD')] + skim_do[('SOVTOLL_TIME', 'MD')]"
15+
decay function,_decay, exp(_auOpTime * dispersion_parameter_automobile)
16+
auto off-peak retail,auOpRetail,df.RETEMPN * _decay
17+
auto off-peak total,auOpTotal,df.TOTEMP * _decay
18+
#,,
19+
#,, transit peak
20+
#,,
21+
#,, assume peak outbound transit occurs in AM
22+
o-d peak transit ivt,_inVehicleTime,"skim_od[('WLK_TRN_WLK_IVT', 'AM')]"
23+
o-d peak transit ovt,_outOfVehicleTime,"skim_od[('WLK_TRN_WLK_IWAIT', 'AM')] + skim_od[('WLK_TRN_WLK_XWAIT', 'AM')] + skim_od[('WLK_TRN_WLK_WACC', 'AM')] + skim_od[('WLK_TRN_WLK_WAUX', 'AM')] + skim_od[('WLK_TRN_WLK_WEGR', 'AM')]"
24+
o-d peak transit time,_trPkTime_od,(_inVehicleTime + out_of_vehicle_time_weight * _outOfVehicleTime) / TRANSIT_SCALE_FACTOR
25+
#,, assume peak inbound transit occurs in PM
26+
d-o peak transit ivt,_inVehicleTime,"skim_do[('WLK_TRN_WLK_IVT', 'PM')]"
27+
d-o peak transit ovt,_outOfVehicleTime,"skim_do[('WLK_TRN_WLK_IWAIT', 'PM')] + skim_do[('WLK_TRN_WLK_XWAIT', 'PM')] + skim_do[('WLK_TRN_WLK_WACC', 'PM')] + skim_do[('WLK_TRN_WLK_WAUX', 'PM')] + skim_do[('WLK_TRN_WLK_WEGR', 'PM')]"
28+
d-o peak transit time,_trPkTime_do,(_inVehicleTime + out_of_vehicle_time_weight * _outOfVehicleTime) / TRANSIT_SCALE_FACTOR
29+
peak transit time,_trPkTime,(_trPkTime_od + _trPkTime_do).clip(0)
30+
round trip path is available,_rt_available,(_trPkTime_od > 0) & (_trPkTime_do > 0)
31+
decay function,_decay,_rt_available * exp(_trPkTime * dispersion_parameter_transit)
32+
transit peak retail,trPkRetail,df.RETEMPN * _decay
33+
transit peak total,trPkTotal,df.TOTEMP * _decay
34+
#,,
35+
#,, transit off-peak
36+
#,,
37+
#,, assume off-peak outbound transit occurs in the MD time period
38+
o-d off-peak transit ivt,_inVehicleTime,"skim_od[('WLK_TRN_WLK_IVT', 'MD')]"
39+
o-d off-peak transit ovt,_outOfVehicleTime,"skim_od[('WLK_TRN_WLK_IWAIT', 'MD')] + skim_od[('WLK_TRN_WLK_XWAIT', 'MD')] + skim_od[('WLK_TRN_WLK_WACC', 'MD')] + skim_od[('WLK_TRN_WLK_WAUX', 'MD')] + skim_od[('WLK_TRN_WLK_WEGR', 'MD')]"
40+
o-d off-peak transit time,_trOpTime_od,(_inVehicleTime + out_of_vehicle_time_weight * _outOfVehicleTime) / TRANSIT_SCALE_FACTOR
41+
#,, assume off-peak inbound transit occurs in the MD time period
42+
d-o off-peak transit ivt,_inVehicleTime,"skim_do[('WLK_TRN_WLK_IVT', 'MD')]"
43+
d-o off-peak transit ovt,_outOfVehicleTime,"skim_do[('WLK_TRN_WLK_IWAIT', 'MD')] + skim_do[('WLK_TRN_WLK_XWAIT', 'MD')] + skim_do[('WLK_TRN_WLK_WACC', 'MD')] + skim_do[('WLK_TRN_WLK_WAUX', 'MD')] + skim_do[('WLK_TRN_WLK_WEGR', 'MD')]"
44+
d-o off-peak transit time,_trOpTime_do,(_inVehicleTime + out_of_vehicle_time_weight * _outOfVehicleTime) / TRANSIT_SCALE_FACTOR
45+
peak transit time,_trOpTime,(_trOpTime_od + _trOpTime_do).clip(0)
46+
#,,FIXME - _rt_available calculation appears to be wrong in mtctm1 accessibility.job
47+
#round trip path is available,_rt_available,(_trOpTime > 0)
48+
round trip path is available,_rt_available,(_trOpTime_od > 0) & (_trOpTime_do > 0)
49+
decay function,_decay,_rt_available * exp(_trOpTime * dispersion_parameter_transit)
50+
transit off-peak retail,trOpRetail,df.RETEMPN * _decay
51+
transit off-peak total,trOpTotal,df.TOTEMP * _decay
52+
#,,
53+
#,, non motorized
54+
#,,
55+
non-motorized round trip distance,_nmDist,skim_od['DISTWALK'] + skim_do['DISTWALK']
56+
round trip path is available,_rt_available,_nmDist <= maximum_walk_distance
57+
decay function,_decay,_rt_available * exp(_nmDist * dispersion_parameter_walk)
58+
retail accessibility,nmRetail,df.RETEMPN * _decay
59+
total accessibility,nmTotal,df.TOTEMP * _decay

configs/accessibility.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
# columns from land_use table to add to df
3+
land_use_columns: ['RETEMPN', 'TOTEMP']
4+
5+
CONSTANTS:
6+
# dispersion parameters
7+
dispersion_parameter_automobile: -0.05
8+
dispersion_parameter_transit: -0.05
9+
dispersion_parameter_walk: -1.00
10+
# maximum walk distance in miles
11+
maximum_walk_distance: 3.0
12+
# perceived minute of in-vehicle time for every minute of out-of-vehicle time
13+
out_of_vehicle_time_weight: 2.0

configs/annotate_households.csv

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Description,Target,Expression
2+
#,,annotate households table after import
3+
,_PERSON_COUNT,"lambda query, persons, households: persons.query(query).groupby('household_id').size().reindex(households.index).fillna(0).astype(np.int8)"
4+
#,,FIXME households.income can be negative - so we clip?
5+
income_in_thousands,income_in_thousands,(households.income / 1000).clip(lower=0)
6+
income_segment,income_segment,"pd.cut(income_in_thousands, bins=[-np.inf, 30, 60, 100, np.inf], labels=[INCOME_SEGMENT_LOW, INCOME_SEGMENT_MED, INCOME_SEGMENT_HIGH, INCOME_SEGMENT_VERYHIGH]).astype(int)"
7+
#,,
8+
,_MIN_VOT,setting('min_value_of_time')
9+
,_MAX_VOT,setting('max_value_of_time')
10+
,_MU,setting('distributed_vot_mu')
11+
,_SIGMA,setting('distributed_vot_sigma')
12+
median_value_of_time,median_value_of_time,"income_segment.map({k: v for k, v in setting('household_median_value_of_time').items()})"
13+
hh_value_of_time,hh_value_of_time,"rng.lognormal_for_df(df, mu=np.log(median_value_of_time * _MU), sigma=_SIGMA).clip(_MIN_VOT, _MAX_VOT)"
14+
#,,
15+
#num_workers was renamed in import,,
16+
#,num_workers,households.workers
17+
number of non_workers,num_non_workers,households.hhsize - households.num_workers
18+
#,,
19+
#,,we assume that everyone 16 and older is a potential driver
20+
number of drivers,num_drivers,"_PERSON_COUNT('16 <= age', persons, households)"
21+
num_adults,num_adults,"_PERSON_COUNT('adult', persons, households)"
22+
num_children,num_children,"_PERSON_COUNT('~adult', persons, households)"
23+
num_young_children,num_young_children,"_PERSON_COUNT('age <= 5', persons, households)"
24+
num_children_5_to_15,num_children_5_to_15,"_PERSON_COUNT('5 <= age <= 15', persons, households)"
25+
num_children_16_to_17,num_children_16_to_17,"_PERSON_COUNT('16 <= age <= 17', persons, households)"
26+
num_college_age,num_college_age,"_PERSON_COUNT('18 <= age <= 24', persons, households)"
27+
num_young_adults,num_young_adults,"_PERSON_COUNT('25 <= age <= 34', persons, households)"
28+
non_family,non_family,households.HHT.isin(HHT_NONFAMILY)
29+
family,family,households.HHT.isin(HHT_FAMILY)
30+
home_is_urban,home_is_urban,"reindex(land_use.area_type, households.home_zone_id) < setting('urban_threshold')"
31+
home_is_rural,home_is_rural,"reindex(land_use.area_type, households.home_zone_id) > setting('rural_threshold')"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Description,Target,Expression
2+
#,, annotate households table after cdap model has run
3+
num_under16_not_at_school,num_under16_not_at_school,persons.under16_not_at_school.astype(int).groupby(persons.household_id).sum().reindex(households.index).fillna(0).astype(np.int8)
4+
num_travel_active,num_travel_active,persons.travel_active.astype(int).groupby(persons.household_id).sum().reindex(households.index).fillna(0).astype(np.int8)
5+
num_travel_active_adults,num_travel_active_adults,(persons.adult & persons.travel_active).astype(int).groupby(persons.household_id).sum().reindex(households.index).fillna(0).astype(np.int8)
6+
num_travel_active_preschoolers,num_travel_active_preschoolers,((persons.ptype == PTYPE_PRESCHOOL) & persons.travel_active).astype(int).groupby(persons.household_id).sum().reindex(households.index).fillna(0).astype(np.int8)
7+
num_travel_active_children,num_travel_active_children,num_travel_active - num_travel_active_adults
8+
num_travel_active_non_preschoolers,num_travel_active_non_preschoolers,num_travel_active - num_travel_active_preschoolers
9+
#participates_in_jtf_model,participates_in_jtf_model,(num_travel_active > 1) & (num_travel_active_non_preschoolers > 0)
10+
participates_in_jtf_model,participates_in_jtf_model,(num_travel_active > 1)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Description,Target,Expression
2+
#,, annotate households table after workplace_location model has run
3+
#,, hh_work_auto_savings_ratio is sum of persons work_auto_savings_ratio
4+
,hh_work_auto_savings_ratio,persons.work_auto_savings_ratio.groupby(persons.household_id).sum().reindex(households.index).fillna(0.0)
5+
#,,handle persons with no location

configs/annotate_landuse.csv

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Description,Target,Expression
2+
#,, annotate landuse table after import
3+
household_density,household_density,land_use.TOTHH / (land_use.RESACRE + land_use.CIACRE)
4+
employment_density,employment_density,land_use.TOTEMP / (land_use.RESACRE + land_use.CIACRE)
5+
density_index,density_index,(household_density *employment_density) / (household_density + employment_density).clip(lower=1)
6+
,is_cbd,land_use.area_type == 1
7+

configs/annotate_persons.csv

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Description,Target,Expression
2+
#,, annotate persons table after import
3+
age_16_to_19,age_16_to_19,"persons.age.between(16, 19)"
4+
age_16_p,age_16_p,persons.age >= 16
5+
adult,adult,persons.age >= 18
6+
male,male,persons.sex == 1
7+
female,female,persons.sex == 2
8+
presence of non_worker other than self in household,has_non_worker,"other_than(persons.household_id, persons.ptype == PTYPE_NONWORK)"
9+
presence of retiree other than self in household,has_retiree,"other_than(persons.household_id, persons.ptype == PTYPE_RETIRED)"
10+
presence of preschooler other than self in household,has_preschool_kid,"other_than(persons.household_id, persons.ptype == PTYPE_PRESCHOOL)"
11+
presence of driving_kid other than self in household,has_driving_kid,"other_than(persons.household_id, persons.ptype == PTYPE_DRIVING)"
12+
presence of school_kid other than self in household,has_school_kid,"other_than(persons.household_id, persons.ptype == PTYPE_SCHOOL)"
13+
presence of full_time worker other than self in household (independent of person type),has_full_time,"other_than(persons.household_id, persons.pemploy==PEMPLOY_FULL)"
14+
presence of part_time worker other than self in household (independent of person type),has_part_time,"other_than(persons.household_id, persons.pemploy==PEMPLOY_PART)"
15+
presence of university student other than self in household,has_university,"other_than(persons.household_id, persons.ptype == PTYPE_UNIVERSITY)"
16+
student_is_employed,student_is_employed,"(persons.ptype.isin([PTYPE_UNIVERSITY, PTYPE_DRIVING]) & persons.pemploy.isin([PEMPLOY_FULL, PEMPLOY_PART]))"
17+
nonstudent_to_school,nonstudent_to_school,"(persons.ptype.isin([PTYPE_FULL, PTYPE_PART, PTYPE_NONWORK, PTYPE_RETIRED]) & persons.pstudent.isin([PSTUDENT_GRADE_OR_HIGH, PSTUDENT_UNIVERSITY]))"
18+
#,,
19+
#,, FIXME - if person is a university student but has school age student category value then reset student category value
20+
,pstudent,"persons.pstudent.where(persons.ptype!=PTYPE_UNIVERSITY, PSTUDENT_UNIVERSITY)"
21+
#,, FIXME if person is a student of any kind but has full-time employment status then reset student category value to non-student
22+
,pstudent,"pstudent.where(persons.ptype!=PTYPE_FULL, PSTUDENT_NOT)"
23+
#,, FIXME if student category is non-student and employment is student then reset student category value to student
24+
,pstudent,"pstudent.where((persons.ptype!=PTYPE_DRIVING) & (persons.ptype!=PTYPE_SCHOOL), PSTUDENT_GRADE_OR_HIGH)"
25+
#,,
26+
is_student,is_student,"pstudent.isin([PSTUDENT_GRADE_OR_HIGH, PSTUDENT_UNIVERSITY])"
27+
preschool age can go to preschool,is_student,"is_student.where(persons.age > GRADE_SCHOOL_MIN_AGE, True)"
28+
preschool age can go to preschool,pstudent,"pstudent.where(persons.age > GRADE_SCHOOL_MIN_AGE, PSTUDENT_GRADE_OR_HIGH)"
29+
is_gradeschool,is_gradeschool,(pstudent == PSTUDENT_GRADE_OR_HIGH) & (persons.age <= GRADE_SCHOOL_MAX_AGE)
30+
is_highschool,is_highschool,(pstudent == PSTUDENT_GRADE_OR_HIGH) & (persons.age > GRADE_SCHOOL_MAX_AGE)
31+
is_university,is_university,pstudent == PSTUDENT_UNIVERSITY
32+
school_segment gradeschool,school_segment,"np.where(is_gradeschool, SCHOOL_SEGMENT_GRADE, SCHOOL_SEGMENT_NONE)"
33+
school_segment highschool,school_segment,"np.where(is_highschool, SCHOOL_SEGMENT_HIGH, school_segment)"
34+
school_segment university,school_segment,"np.where(is_university, SCHOOL_SEGMENT_UNIV, school_segment).astype(np.int8)"
35+
#,,
36+
is_worker,is_worker,"persons.pemploy.isin([PEMPLOY_FULL, PEMPLOY_PART])"
37+
#,,
38+
home_zone_id,home_zone_id,"reindex(households.home_zone_id, persons.household_id)"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Description,Target,Expression
2+
#,, annotate persons table after annotate_households
3+
#,, adults get full hh_value_of_time and children get 60%
4+
,_hh_vot,"reindex(households.hh_value_of_time, persons.household_id)"
5+
,value_of_time,"_hh_vot.where(persons.age>=18, _hh_vot * 0.667)"

0 commit comments

Comments
 (0)