CT-RAMP Formatting
Overview
The format_ctramp step transforms canonical survey data (households, persons, tours, and trips)
into the file format used by
CT-RAMP
(Coordinated Travel – Regional Activity Modeling Platform), MTC's activity-based travel demand
model for the nine-county Bay Area.
This formatted output enables direct comparison between observed survey behavior and model-simulated behavior: the survey tables and model output tables share an identical schema, so any summary statistic computed on model output can be replicated on the survey to measure how well the model reproduces observed travel patterns.
Background: BATS vs. CT-RAMP
BATS (Bay Area Travel Study) is a GPS-tracked travel diary survey. Respondents carry a device for several days and their trips are logged automatically. Raw survey data is therefore organized around individual trips: each record is a single movement from one place to another.
CT-RAMP is a tour-based model. Rather than simulating each trip in isolation, it groups trips into tours — sequences of trips that begin and end at a fixed anchor location (usually home, or the work place for at-work sub-tours). Every stop along a tour is a trip in the raw survey, but CT-RAMP treats the entire tour as the unit of analysis.
Bridging these two representations is the core job of the pipeline steps that precede
format_ctramp:
| Pipeline step | What it does |
|---|---|
load_data, clean_<project> |
Reads the survey tables and recodes them to the canonical schema |
link_trips |
Joins trip segments into linked trips |
detect_habitual_locations |
Finds each person's home, workplace and school |
detect_joint_trips |
Identifies trips shared among household members |
extract_tours |
Groups linked trips into home-based tours, subtours and joint tours |
add_zone_ids |
Assigns TAZ (and other zones) to every location |
cascade_completeness |
Stamps usable_<profile> for each profile, ctramp among them |
compute_weights |
Fits one weight set per profile, hh_weight_ctramp among them |
format_ctramp |
Translates canonical tours/trips into CT-RAMP schema |
By the time format_ctramp runs, the canonical data is already in a tour-based structure that
mirrors CT-RAMP's expectations. The remaining work is renaming columns, encoding categorical
variables and applying income-based segmentation. Which records are written is not decided here:
the step keeps the records its usability_profile admits (the usable_<profile> column), and
reads that profile's weights.
Output Tables
format_ctramp produces eleven tables that mirror the CT-RAMP model output files: households,
persons, individual and joint tours, individual and joint trips, mandatory locations, all tours,
all trips, and the CDAP and auto ownership results.
See CT-RAMP Data Models for the table listing and field-level schema
documentation.
Key Transformations
Income segmentation
BATS collects income as a categorical bracket (e.g. $50,000–$74,999). CT-RAMP encodes work tour
purpose as a function of household income — work_low, work_med, work_high, or
work_very_high — because higher-income workers have different mode choice sensitivities.
The pipeline converts the categorical bracket to a dollar midpoint (in survey-year 2023
dollars), converts it to year-2000 dollars (multiplying by income_survey_year_to_ctramp_year, since
CT-RAMP income categories are in year-2000 dollars), then classifies it against configurable
thresholds (set in the config via income_low_threshold, income_med_threshold,
income_high_threshold; see CTRAMPConfig).
The thresholds are in year-2000 dollars, matching MTC CT-RAMP
INCOME_SEGMENT_DOLLAR_LIMITS = {30000, 60000, 100000, MAX}.
Person type
CT-RAMP distinguishes eight person types that drive the model's choice structure (e.g., children of non-driving age make no mode choice; retired persons have different activity patterns than full-time workers). Person type is derived from three BATS fields:
| BATS fields | CT-RAMP person type |
|---|---|
employment = EMPLOYED_FULLTIME or EMPLOYED_SELF |
Full-time worker (1) |
employment = EMPLOYED_PARTTIME |
Part-time worker (2) |
| University / vocational student (not employed FT/PT) | University student (3) |
| Not employed, not student, not retired, age ≥ 18 | Non-worker (4) |
employment = RETIRED |
Retired (5) |
| High-school student, age 16–17 | Student of driving age (6) |
| Elementary / middle-school student, or age 5–15 | Student of non-driving age (7) |
| Age < 5 | Child too young for school (8) |
Purpose mapping
BATS uses a single PurposeCategory for all trips. CT-RAMP needs more detail:
- Work trips are further split by income bracket (see above).
- School trips split into grade school, high school, and university based on
school_type. - At-work sub-tours (tours that begin and end at the work place rather than home) use dedicated
CT-RAMP purposes:
atwork_business,atwork_eat,atwork_maint. - Escort trips split into
escort_kidsvs.escort_no_kidsdepending on whether the household contains school-age children. - All remaining BATS purposes (
ERRAND,SHOP,MEAL,SOCIALREC, etc.) map to direct CT-RAMP equivalents.
Mode mapping
BATS records a single ModeType per trip. CT-RAMP encodes 21 mode codes that distinguish
drive-alone, shared ride (2 or 3+), walk/bike, transit access/egress combinations (walk-to-bus,
drive-to-rail, etc.), taxi, and TNC. Transit modes are further refined using access-egress
information recorded in the linked trip data.
Joint tours
Joint tours are built by extract_tours from the joint trips detect_joint_trips found. They are
written to the joint tour and trip tables, rather than the individual ones, when the profile
admits them: CT-RAMP draws a joint tour's trips once for everyone on it, so the ctramp profile
sets joint_tours: fully_joint, and a tour someone leaves for a leg becomes individual tours. The joint_tours_ctramp table
records tour composition (adults only, children only, or mixed) and the participating person list.
Spatial fields (TAZ)
CT-RAMP operates on Transportation Analysis Zones (TAZ). Home, work, and school locations are
snapped to TAZ centroids by the upstream add_zone_ids step. format_ctramp selects which
TAZ geography to use (configurable via taz_field, e.g. TAZ1454). A record without a TAZ is
left out by the profile, not by this step: the ctramp profile sets zone_coverage to that zone
system.
Fields Not Derivable from Survey Data
Several CT-RAMP output fields are model artefacts that cannot be reconstructed from survey
responses. These are omitted from the survey-formatted tables (left as null) and should be
ignored when using the survey files for calibration:
| Field | Why it is model-only |
|---|---|
walk_subzone |
Computed from network skims at run time |
humanVehicles / autonomousVehicles |
AV fleet composition is a model scenario input |
auto_suff |
Incorrectly coded in original spec; always ignored |
ao_rn, cdap_rn, imtf_rn, … (all *_rn fields) |
Random-number seeds set during Monte Carlo simulation |
value_of_time |
Calculated internally by the model from income and person type coefficients |
sampleRate |
Set equal to 1 / hh_weight for survey records; actual model value is determined by the synthetic population sampling rate |
Using the Output for Calibration
Once format_ctramp has run, the output CSVs can be loaded alongside CT-RAMP model output files
and compared field-by-field. Common calibration checks include:
- Activity pattern shares (
activity_patterninpersons_ctramp): compare % with mandatory / non-mandatory / home patterns between survey and model. - Tour frequency (
imf_choice,inmf_choice): check distributions of mandatory and non-mandatory tour counts per person. - Joint tour frequency (
jtf_choiceinhouseholds_ctramp): compare households by joint tour type and count. - Mode shares (
tour_mode,trip_mode): compare mode distributions by purpose and person type. - Time-of-day (
start_hour,end_hourin tour tables): compare departure and arrival time distributions.
The sampleRate field in households_ctramp (= 1 / hh_weight) allows these comparisons to be
made on a weighted basis, matching what the model sees from its synthetic population.
Configuration Reference
As set in projects/bats_2023/config.yaml:
- name: format_ctramp
params:
usability_profile: ctramp # the records kept, and the weights read
income_low_threshold: 30000 # below → work_low ($2000)
income_med_threshold: 60000 # below → work_med ($2000)
income_high_threshold: 100000 # below → work_high, above → work_very_high ($2000)
income_survey_year_to_ctramp_year: 0.5319148936 # = 1 / 1.88
age_adult: 4 # AgeCategory enum value; 4 = AGE_18_TO_24+
gender_default_for_missing: "f" # CT-RAMP requires binary gender
taz_field: "TAZ1454" # Which zone geography to use
Settings
| Key | Type | Default | Meaning |
|---|---|---|---|
income_low_threshold |
whole number, ≥ 0 | required | Income threshold for low income bracket (in dollars). Income below this is classified as 'work_low'. Example: 60000 for $60k annual income |
income_med_threshold |
whole number, ≥ 0 | required | Income threshold for medium income bracket (in dollars). Household income below this threshold (but above low) is classified as 'work_med'. Example: 150000 for $150k annual income |
income_high_threshold |
whole number, ≥ 0 | required | Income threshold for high income bracket (in dollars). Household income below this threshold (but above med) is classified as 'work_high'. Above this is 'work_very high'. Example: 240000 for $240k annual income |
taz_field |
text | required | The field name in the household data that contains the TAZ ID for CTRAMP formatting. |
usability_profile |
text | required | Which usability profile stamped by cascade_completeness decides the record universe. Required, and must name a profile that run stamped: a looser profile admits more, at the cost of no longer matching whichever profile the weighting and the other formatters were given. |
age_adult |
whole number, ≥ 0 | required | Age category threshold for adult vs child in joint tours. Use AgeCategory enum value (e.g., 4 = AGE_18_TO_24 and higher are adults). |
income_survey_year_to_ctramp_year |
number, > 0 | required | Factor to convert survey-year dollars to CT-RAMP-year dollars. Survey income is multiplied by this factor. For BATS 2023 -> CT-RAMP year 2000 the factor is 1 / 1.88 ~= 0.532 (2000 -> 2023 inflation is 1.88) per https://github.com/BayAreaMetro/modeling-website/wiki/InflationAssumptions |
gender_default_for_missing |
text | required | Gender ('m' or 'f') given to missing/non-binary values, since CT-RAMP requires binary gender. |
fixed_location_buffer_meters |
number, ≥ 0 | 200.0 |
Spatial buffer in meters for matching fixed work/school locations to trip destinations when calculating distances. |
distance_unit |
text | miles |
Distance unit for CT-RAMP formatting ('miles', 'kilometers', or 'meters'). |