Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 34 additions & 40 deletions activitysim/abm/models/trip_matrices.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class MatrixTableSettings(PydanticReadable):
class MatrixSettings(PydanticReadable):
file_name: Path
tables: list[MatrixTableSettings] = []
is_tap: bool = False


class WriteTripMatricesSettings(PydanticReadable):
Expand Down Expand Up @@ -62,9 +61,7 @@ def write_trip_matrices(
then aggregates trip counts and writes OD matrices to OMX. Save annotated
trips table to pipeline if desired.

Writes taz trip tables for one and two zone system. Add ``is_tap:True`` to
the settings file to identify an output matrix as tap level trips as opposed
to taz level trips.
Writes taz trip tables for one and two zone system.

For one zone system, uses the land use table for the set of possible tazs.
For two zone system, uses the taz skim zone names for the set of possible
Expand Down Expand Up @@ -351,7 +348,6 @@ def write_matrices(
orig_index,
dest_index,
model_settings: WriteTripMatricesSettings,
is_tap=False,
):
"""
Write aggregated trips to OMX format.
Expand All @@ -371,42 +367,40 @@ def write_matrices(
logger.error("Missing MATRICES setting in write_trip_matrices.yaml")

for matrix in matrix_settings:
matrix_is_tap = matrix.is_tap

if matrix_is_tap == is_tap: # only write tap matrices to tap matrix files
filename = str(matrix.file_name)
filepath = state.get_output_file_path(filename)
logger.info("opening %s" % filepath)
file = omx.open_file(str(filepath), "w") # possibly overwrite existing file
table_settings = matrix.tables

for table in table_settings:
table_name = table.name
col = table.data_field

if col not in aggregate_trips:
logger.error(f"missing {col} column in aggregate_trips DataFrame")
return

hh_weight_col = model_settings.HH_EXPANSION_WEIGHT_COL
if hh_weight_col:
aggregate_trips[col] = (
aggregate_trips[col] / aggregate_trips[hh_weight_col]
)

data = np.zeros((len(zone_index), len(zone_index)))
data[orig_index, dest_index] = aggregate_trips[col]
logger.debug(
"writing %s sum %0.2f" % (table_name, aggregate_trips[col].sum())

filename = str(matrix.file_name)
filepath = state.get_output_file_path(filename)
logger.info("opening %s" % filepath)
file = omx.open_file(str(filepath), "w") # possibly overwrite existing file
table_settings = matrix.tables

for table in table_settings:
table_name = table.name
col = table.data_field

if col not in aggregate_trips:
logger.error(f"missing {col} column in aggregate_trips DataFrame")
return

hh_weight_col = model_settings.HH_EXPANSION_WEIGHT_COL
if hh_weight_col:
aggregate_trips[col] = (
aggregate_trips[col] / aggregate_trips[hh_weight_col]
)
file[table_name] = data # write to file

# include the index-to-zone map in the file
logger.info(
"adding %s mapping for %s zones to %s"
% (zone_index.name, zone_index.size, filename)
data = np.zeros((len(zone_index), len(zone_index)))
data[orig_index, dest_index] = aggregate_trips[col]
logger.debug(
"writing %s sum %0.2f" % (table_name, aggregate_trips[col].sum())
)
file.create_mapping(zone_index.name, zone_index.to_numpy())
file[table_name] = data # write to file

# include the index-to-zone map in the file
logger.info(
"adding %s mapping for %s zones to %s"
% (zone_index.name, zone_index.size, filename)
)
file.create_mapping(zone_index.name, zone_index.to_numpy())

logger.info("closing %s" % filepath)
file.close()
logger.info("closing %s" % filepath)
file.close()
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Transform the TM1 TAZ-based model 25 zone inputs to a two-zone (MAZ and TAZ) set of inputs for software development.
#
# The 25 zones are downtown San Francisco and they are converted to 25 MAZs.
# MAZs 1,2,3,4 are small and adjacent and assigned TAZ 2 and TAP 10002.
# MAZs 13,14,15 are small and adjacent and as signed TAZ 14 and TAP 10014.
# MAZs 1,2,3,4 are small and adjacent and assigned TAZ 2.
# MAZs 13,14,15 are small and adjacent and as signed TAZ 14.
# TAZs 1,3,4,13,15 are removed from the final data set.
#
# This script should work for the full TM1 example as well.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Transform the TM1 TAZ-based model 25 zone inputs to a two-zone (MAZ and TAZ) set of inputs for software development.
#
# The 25 zones are downtown San Francisco and they are converted to 25 MAZs.
# MAZs 1,2,3,4 are small and adjacent and assigned TAZ 2 and TAP 10002.
# MAZs 13,14,15 are small and adjacent and as signed TAZ 14 and TAP 10014.
# MAZs 1,2,3,4 are small and adjacent and assigned TAZ 2.
# MAZs 13,14,15 are small and adjacent and as signed TAZ 14.
# TAZs 1,3,4,13,15 are removed from the final data set.
#
# This script should work for the full TM1 example as well.
Expand Down
44 changes: 0 additions & 44 deletions docs/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -354,50 +354,6 @@ API
.. automodule:: activitysim.core.timetable
:members:

.. _transit_virtual_path_builder:

Transit Virtual Path Builder
----------------------------

Transit virtual path builder (TVPB) for three zone system (see :ref:`multiple_zone_systems`) transit path utility calculations.
TAP to TAP skims and walk access and egress times between MAZs and TAPs are input to the
demand model. ActivitySim then assembles the total transit path utility based on the user specified TVPB
expression files for the respective components:

* from MAZ to first boarding TAP +
* from first boarding to final alighting TAP +
* from alighting TAP to destination MAZ

This assembling is done via the TVPB, which considers all the possible combinations of nearby boarding and alighting TAPs for each origin
destination MAZ pair and selects the user defined N best paths to represent the transit mode. After selecting N best paths, the logsum across
N best paths is calculated and exposed to the mode choice models and a random number is drawn and a path is chosen. The boarding TAP,
alighting TAP, and TAP to TAP skim set for the chosen path is saved to the chooser table.

The initialize TVPB submodel (see :ref:`initialize_los`) pre-computes TAP to TAP total utilities for the user defined attribute_segments,
which are typically demographic segment (for example household income bin), time-of-day, and access/egress mode. This submodel can be
run in both single process and multiprocess mode, with single process excellent for development/debugging and multiprocess excellent
for application. ActivitySim saves the pre-calculated TAP to TAP total utilities to a memory mapped cache file for reuse by downstream models
such as tour mode choice. In tour mode choice, the pre-computed TAP to TAP total utilities for the attribute_segment, along with the
access and egress impedances, are used to evaluate the best N TAP pairs for each origin MAZ destination MAZ pair being evaluated.
Assembling the total transit path impedance and then picking the best N is quick since it is done in a de-duplicated manner within
each chunk of multiprocessed choosers.

A model with TVPB can take considerably longer to run than a traditional TAZ based model since it does an order of magnitude more
calculations. Thus, it is important to be mindful of your approach to your network model as well, especially the number of TAPs
accessible to each MAZ, which is the key determinant of runtime.

API
~~~

.. automodule:: activitysim.core.pathbuilder
:members:


Cache API
~~~~~~~~~

.. automodule:: activitysim.core.pathbuilder_cache
:members:

.. _visualization:

Expand Down
36 changes: 4 additions & 32 deletions docs/users-guide/model_anatomy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ indicators (e.g. skims), the model uses different spatial resolutions for differ
modeling burden and model runtimes. The typical multiple zone system setup is a TAZ zone system for auto travel, a MAZ zone
system for non-motorized travel, and optionally a transit access points (TAPs) zone system for transit.

The three versions of multiple zone systems are one-zone, two-zone, and three-zone.
The two versions of zone systems are one-zone and two-zone.

* **One-zone**: This version is based on TM1 and supports only TAZs. All origins and
destinations are represented at the TAZ level, and all skims including auto, transit,
Expand All @@ -65,45 +65,17 @@ The three versions of multiple zone systems are one-zone, two-zone, and three-zo
walk access and egress times with times specified in the MAZ file by transit mode.
Careful pre-calculation of the assumed transit walk access and egress time by MAZ
and transit mode is required depending on the network scenario.
* **Three-zone**: This version is based on the SANDAG generation of CT-RAMP models.
Origins and destinations are represented at the MAZ level. Impedance for walk or
bike all-the-way from the origin to the destination can be specified at the MAZ
level for close together origins and destinations, and at the TAZ level for further
origins and destinations, just like the two-zone system. TAZs are used for auto
times and costs. The difference between this system and the two-zone system is that
transit times and costs are represented between Transit Access Points (TAPs), which
are essentially dummy zones that represent transit stops or clusters of stops.
Transit skims are built between TAPs, since there are typically too many MAZs to
build skims between them. Often multiple sets of TAP to TAP skims (local bus only,
all modes, etc.) are created and input to the demand model for consideration. Walk
access and egress times are also calculated between the MAZ and the TAP, and total
transit path utilities are assembled from their respective components - from MAZ to
first boarding TAP, from first boarding to final alighting TAP, and from alighting
TAP to destination MAZ.

.. caution::
The ActivitySim consortium is moving away from the three-zone approach, in favor of
to the one- or two-zone approaches. The three-zone system has been removed as of version 1.5.2.
Historically, there was also a three-zone option. The three-zone system has been
removed as of version 1.5.2.

Regions that have an interest in more precise transit and non-motorized forecasts
may wish to adopt the two-zone approach, while other regions may adopt the one or two-zone approach. The
microzone version requires coding households and land use at the microzone level.
Typically an all-streets network is used for representation of non-motorized impedances.
This requires a routable all-streets network, with centroids and connectors for
microzones. If the three-zone system is adopted, procedures need to be developed to
code TAPs from transit stops and populate the all-street network with TAP centroids
and centroid connectors. A model with transit virtual path building takes longer to
run than a traditional TAZ only model, but it provides a much richer framework for
transit modeling.

.. note::
The two and three zone system test examples are simple test examples developed from the TM1 example. To develop the two zone system
example, TM1 TAZs were labeled MAZs, each MAZ was assigned a TAZ, and MAZ to MAZ impedance files were created from the
TAZ to TAZ impedances. To develop the three zone example system example, the TM1 TAZ model was further transformed
so select TAZs also became TAPs and TAP to TAP skims and MAZ to TAP impedances files were created. While sufficient for
initial development, these examples were insufficient for validation and performance testing of the new software. As a result,
the :ref:`prototype_marin` example was created.

microzones.

.. _omx_skims :

Expand Down
Loading