Park-and-Ride Lot Choice#
The park-and-ride lot choice model selects a candidate parking zone for a tour, so that mode choice can evaluate driving to that lot and taking transit to the primary destination. Optional iteration with tour mode choice redistributes excess demand at lots with limited capacity. This functionality was added in PR #1001.
A selected lot does not mean that the tour uses park-and-ride: tour mode choice
still selects the mode. Use both tour_mode and pnr_zone_id to identify actual
park-and-ride demand. Lot choice is distinct from
Parking Location Choice, which selects parking for individual
trips near their destinations.
Structure#
Configuration File:
park_and_ride_lot_choice.yamlCore Table:
tours, with chooser attributes fromtours_mergedAlternatives:
land_usezones with positive park-and-ride spacesResult Field:
pnr_zone_idontours;-1indicates no lot choiceChooser Keys:
home_zone_id,destination,start,end
The model evaluates a utility specification for each eligible chooser and lot using interaction simulation. Lots are represented at the land-use zone level; spaces at multiple facilities in the same zone must be aggregated. Lot zone IDs must be compatible with the default skim dictionary.
Configuring an Implementation#
The fragments below illustrate the configuration structure; the land-use fields, skim names, utility expressions, coefficients, and mode names must be supplied for the implementing model.
Add a column to
land_userepresenting the number of park-and-ride spaces (e.g. pnr_spaces) in that zone. Only zones >= 0 park-and-ride spaces are eligible alternatives for the model.Add
park_and_ride_lot_choiceto themodelslist insettings.yamlafter the relevant tour destinations and schedules are available and beforetour_mode_choice_simulate. Keep this step in the model list when enabling capacity iteration; multiprocessing also uses its presence to allocate shared capacity buffers.Create
park_and_ride_lot_choice.yamland its specification and coefficient files. For example:SPEC: park_and_ride_lot_choice.csv COEFFICIENTS: park_and_ride_lot_choice_coefficients.csv LANDUSE_PNR_SPACES_COLUMN: pnr_spaces LANDUSE_COL_FOR_PNR_ELIGIBLE_DEST: pnr_eligible_destination ITERATE_WITH_TOUR_MODE_CHOICE: false
Here,
pnr_eligible_destinationis a boolean column inland_use. The model first filters destinations for transit eligibility, then runs the chooserpreprocessor, applies the optionalCHOOSER_FILTER_EXPRas a pandas query, and runsalts_preprocessoron lot alternatives.Update the tour mode choice specification and preprocessors to use the selected lot and its access/transit skims. Make park-and-ride modes unavailable when
pnr_zone_id == -1, and guard skim expressions against that sentinel. The lot-choice step does not impose mode availability.Configure trip mode choice and matrix output consistently with the tour mode and selected lot. See Write Trip Matrices for assigning the drive and transit portions to different origin/destination pairs.
Instead of a land-use eligibility column, set TRANSIT_SKIMS_FOR_ELIGIBILITY
to a list of skim names. A destination is eligible if at least one lot has a
positive value to it in any listed skim. Time-dependent skim names use the
form TRANSIT_TIME__AM. If both eligibility settings are supplied, the land-use
column takes precedence; if neither is supplied, all destinations are eligible.
This is a destination screen, so the utility specification must still handle
unavailable paths for individual lot/destination pairs. Filtered-out tours
receive pnr_zone_id = -1.
Skims and Utility Expressions#
The following wrappers are available in lot choice and, when pnr_zone_id is
present, primary tour mode choice. Here, origin is home_zone_id, lot is
pnr_zone_id, and destination is the tour’s primary destination.
Wrapper |
From / to |
Time period |
|---|---|---|
|
Origin to lot |
Outbound ( |
|
Lot to destination |
Outbound ( |
|
Destination to lot |
Inbound ( |
|
Lot to origin |
Inbound ( |
|
Origin to lot |
Time independent |
|
Lot to destination |
Time independent |
For example, a lot-choice CSV specification can include
@olt_skims['DRIVE_TIME'] and @ldt_skims['TRANSIT_TIME'], as well as the
return-leg equivalents, with the implementing model’s skim names and
coefficients. The alternative attributes include pnr_zone_id and
pnr_lot_full. When iteration is disabled, pnr_lot_full is zero.
Capacity Iteration#
To enable capacity feedback, add the following to
park_and_ride_lot_choice.yaml, replacing PNR_TRANSIT with the applicable
mode names from the tour mode choice specification:
ITERATE_WITH_TOUR_MODE_CHOICE: true
MAX_ITERATIONS: 5
PARK_AND_RIDE_MODES: [PNR_TRANSIT]
ACCEPTED_TOLERANCE: 0.95
RESAMPLE_STRATEGY: latest
TRACE_PNR_CAPACITIES_PER_ITERATION: true
The first mode-choice pass includes all primary tours. Capacity accounting then
counts only tours choosing a mode in PARK_AND_RIDE_MODES. Excess tours are
selected for a new lot choice and mode choice; other tours keep their results.
The final lot and mode choices are written back to tours.
Capacity is scaled to the simulated population as
ceil(spaces * sample_rate), using the modal value of households.sample_rate.
Occupancy counts tours, not persons or time-dependent parking stays. The
implementation does not release spaces at tour end times. latest uses the
tour start to select excess tours in descending start-time order, with tour
ID breaking ties. random selects occupants with probability
(occupancy - capacity) / occupancy, so the number resampled equals the excess
in expectation.
ACCEPTED_TOLERANCE (default 0.95) flags a lot as full when occupancy reaches
ceil(scaled_capacity * ACCEPTED_TOLERANCE). Resampling addresses demand above
the full scaled capacity, not above the tolerance threshold. Flagged lots remain
in the alternatives with pnr_lot_full = 1: the lot-choice specification must
use this flag to discourage or exclude them. They are not automatically
removed. If all alternatives are flagged full, lot choice returns -1 and the
mode-choice specification must allow a non-park-and-ride alternative.
MAX_ITERATIONS (default 5) includes the initial mode-choice pass; use a
value greater than one to allow resampling. Iteration can stop earlier when no
choosers need resimulation. Capacity iteration is disabled during estimation.
Reaching the iteration limit does not guarantee that every lot meets capacity.
When TRACE_PNR_CAPACITIES_PER_ITERATION is true (the default), capacity checks
write pnr_capacity_snapshot_i<N> traces containing scaled capacity,
occupancy, percent utilized, excess demand, and the capacitated flag. Checks
occur before resampling, not after the final allowed mode-choice pass. Inspect
final tour choices as well as these traces when assessing remaining excess
demand.
Logsums and At-Work Subtours#
Set include_pnr_for_logsums: true in the tour mode settings used for logsum
calculations to select a lot for each logsum chooser OD pair and expose the
lot skims in the logsum utility calculations. This also supports disaggregate
accessibility calculations. These lot choices are uncapacitated and can add
runtime. Lot-choice preprocessors used here must tolerate tables such as
tours not existing yet; guard expressions that depend on those tables.
Set run_atwork_pnr_lot_choice: true in the settings used by
At-work Subtour Mode to select lots for at-work subtours.
This uses workplace_zone_id as the origin and does not apply the primary-tour
capacity iteration. Both settings default to false.
Configuration#
- settings activitysim.abm.models.park_and_ride_lot_choice.ParkAndRideLotChoiceSettings#
Bases:
LogitComponentSettingsCreate a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- Config:
extra: str = forbid
- Fields:
- Validators:
update_sharrow_skip»all fields
- field ACCEPTED_TOLERANCE: float = 0.95#
Lot is considered full if the lot is at least this percentage full.
- Validated by:
update_sharrow_skip
- field CHOOSER_FILTER_EXPR: str | None = None#
An optional expression to filter the chooser table before simulating the model. Applied after preprocessing as a .query() expression.
- Validated by:
update_sharrow_skip
- field COEFFICIENTS: Path | None = None#
Coefficients filename.
This is a CSV file giving named parameters for use in the utility expression. If it is not provided, then it is assumed that all model coefficients are given explicitly in the SPEC as numerical values instead of named parameters. This is perfectly acceptable for use with ActivitySim for typical simulation applications, but may be problematic if used with “estimation mode”.
- Validated by:
update_sharrow_skip
- field CONSTANTS: dict[str, Any] = {}#
Named constants usable in the utility expressions.
- Validated by:
update_sharrow_skip
- field ITERATE_WITH_TOUR_MODE_CHOICE: bool = False#
If True, iterate with tour mode choice to find un-capacitated pnr lots.
- Validated by:
update_sharrow_skip
- field LANDUSE_COL_FOR_PNR_ELIGIBLE_DEST: str | None = None#
The column name in the land use table that indicates whether a destination is eligible for park-and-ride. If supplied, then TRANSIT_SKIMS_FOR_ELIGIBILITY is not used.
- Validated by:
update_sharrow_skip
- field LANDUSE_PNR_SPACES_COLUMN: str [Required]#
lists the column name in the land use table that contains the number of park-and-ride spaces available in the zone
- Validated by:
update_sharrow_skip
- field LOGIT_TYPE: Literal['MNL', 'NL'] = 'MNL'#
Logit model mathematical form.
- “MNL”
Multinomial logit model.
- “NL”
Nested multinomial logit model.
- Validated by:
update_sharrow_skip
- field MAX_ITERATIONS: int = 5#
Maximum number of iterations to iterate park-and-ride choice with tour mode choice.
- Validated by:
update_sharrow_skip
- field NESTS: LogitNestSpec | None = None#
Nesting structure for a nested logit model.
The nesting structure is specified heirarchically from the top, so the value of this field should be the “root” level nest of the nested logit tree, which should contain references to lower level nests and/or the actual alternatives.
For example, this YAML defines a simple nesting structure for four alternatives (DRIVE, WALK, WALK_TO_TRANSIT, DRIVE_TO_TRANSIT) with the two transit alternatives grouped together in a nest:
NESTS: name: root coefficient: coef_nest_root alternatives: - DRIVE - WALK - name: TRANSIT coefficient: coef_nest_transit alternatives: - WALK_TO_TRANSIT - DRIVE_TO_TRANSIT
- Validated by:
update_sharrow_skip
- field PARK_AND_RIDE_MODES: list[str] | None = None#
List of modes that are considered park-and-ride modes. Needed for filtering choices to calculate park-and-ride lot capacities. Should correspond to the columns in the tour mode choice specification file.
- Validated by:
update_sharrow_skip
- field RESAMPLE_STRATEGY: Literal['latest', 'random'] = 'latest'#
Strategy to use when selecting tours for resampling park-and-ride lot choices. - latest: tours arriving the latest are selected for resampling. - random: randomly resample from all tours at the over-capacitated lot.
- Validated by:
update_sharrow_skip
- field SPEC: Path [Required]#
Utility specification filename.
This is sometimes alternatively called the utility expressions calculator (UEC). It is a CSV file giving all the functions for the terms of a linear-in-parameters utility expression.
- Validated by:
update_sharrow_skip
- field TRACE_PNR_CAPACITIES_PER_ITERATION: bool = True#
If True, output park-and-ride lot occupancy at each iteration to the trace folder.
- Validated by:
update_sharrow_skip
- field TRANSIT_SKIMS_FOR_ELIGIBILITY: list[str] | None = None#
A list of skim names to use for filtering choosers to only those with destinations that have transit access. If None, all tours are considered eligible for park-and-ride lot choice.
- Validated by:
update_sharrow_skip
- field alts_preprocessor: PreprocessorSettings | None = None#
Preprocessor settings for park-and-ride lot alternatives.
- Validated by:
update_sharrow_skip
- field annotate_households: PreprocessorSettings | None = None#
Annotate households output tables with additional columns.
These settings are used to add additional columns to the output tables after the logit model is run. They are typically used to add additional attributes that are derived from the model results.
- Validated by:
update_sharrow_skip
- field annotate_persons: PreprocessorSettings | None = None#
Annotate persons output tables with additional columns.
- Validated by:
update_sharrow_skip
- field annotate_tours: PreprocessorSettings | None = None#
Annotate tours output tables with additional columns.
- Validated by:
update_sharrow_skip
- field annotate_trips: PreprocessorSettings | None = None#
Annotate trips output tables with additional columns.
- Validated by:
update_sharrow_skip
- field annotate_vehicles: PreprocessorSettings | None = None#
Annotate vehicles output tables with additional columns.
- Validated by:
update_sharrow_skip
- field compute_settings: ComputeSettings = ComputeSettings(sample_method=None, sharrow_skip=False, fastmath=False, use_bottleneck=None, use_numexpr=None, use_numba=None, drop_unused_columns=True, protect_columns=[], performance_log=None)#
Sharrow settings for this component.
- Validated by:
update_sharrow_skip
- field explicit_chunk: float = 0#
If > 0, use this chunk size instead of adaptive chunking. If less than 1, use this fraction of the total number of rows.
- Validated by:
update_sharrow_skip
- field preprocessor: PreprocessorSettings | list[PreprocessorSettings] | None = None#
Chooser preprocessor settings.
This is a set of expressions to be evaluated on the choosers before the logit model is run. It is used to prepare the choosers for the logit model by adding columns that are used in the utility expressions.
- Validated by:
update_sharrow_skip
- field source_file_paths: list[Path] = None#
A list of source files from which these settings were loaded.
This value should not be set by the user within the YAML settings files, instead it is populated as those files are loaded. It is primarily provided for debugging purposes, and does not actually affect the operation of any model.
- Validated by:
update_sharrow_skip
- classmethod nests_are_for_nl(nests, values)#
Checks that nests are provided if (and only if) LOGIT_TYPE is NL.
- validator update_sharrow_skip » all fields#
Implementation#
- activitysim.abm.models.park_and_ride_lot_choice.park_and_ride_lot_choice(state: State, tours: DataFrame, tours_merged: DataFrame, land_use: DataFrame, network_los: Network_LOS, model_settings: ParkAndRideLotChoiceSettings | None = None, model_settings_file_name: str = 'park_and_ride_lot_choice.yaml', trace_label: str = 'park_and_ride_lot_choice', trace_hh_id: bool = False) None#
This model predicts which lot location would be used for a park-and-ride tour.
- activitysim.abm.models.park_and_ride_lot_choice.run_park_and_ride_lot_choice(state: State, choosers: DataFrame, land_use: DataFrame, network_los: Network_LOS, model_settings: ParkAndRideLotChoiceSettings | None = None, choosers_dest_col_name: str = 'destination', choosers_origin_col_name: str = 'home_zone_id', estimator=None, model_settings_file_name: str = 'park_and_ride_lot_choice.yaml', pnr_capacity_cls: ParkAndRideCapacity | None = None, trace_label: str = 'park_and_ride_lot_choice') Series#
Run the park-and-ride lot choice model.
Provides another entry point for the model which is useful for getting pnr locations while creating logsums.