Describe the bug
Simulation shadow pricing can use an inconsistent workplace segment column and silently resimulate the wrong persons, or no persons at all.
This is happening in the SANDAG example model, and highly likely in the SANDAG production model, and in some agencies' current ActivitySim implementation, if they use the simulation method for shadow pricing and do not segment by income. This is easy to miss because the run can continue without an exception. See the attached log file showing no choosers were resimulated in workplace location in the full size SANDAG example model run (search for workplace_location.i2).
mp_households_0-activitysim.log
With the simulation-based method, shadow pricing uses SEGMENT_TO_NAME (defaulted to income_segment) to choose a persons_merged segment field, then filters persons by equality with workplace SEGMENT_IDS. If user segments the workplace location by occupation (or another field) and does not specify SEGMENT_TO_NAME in the shadow pricing yaml, the filter is inconsistent.
This creates two failure modes:
- No overlap (for example string occupation
segment_ids in the SANDAG example, vs the default numeric income_segment), so zero persons are sampled and resimulated for intended segments.
- Accidental numeric overlap, so persons are sampled and resimulated from the wrong segmentation basis.
Relevant code path:
To Reproduce
Steps to reproduce the behavior:
- Use a model with simulation shadow pricing enabled (
SHADOW_PRICE_METHOD: simulation), for example sandag-abm3-example/configs/resident/shadow_pricing.yaml.
- Configure workplace location to segment choosers by
occupation and occupation-based SEGMENT_IDS, for example sandag-abm3-example/configs/resident/workplace_location.yaml.
- Run the model and inspect simulation shadow-pricing resampling behavior.
- Observe that resampling and resimulation is incorrect:
- either no sampled persons for intended segments (no-overlap case, the example sandag model), or
- sampled persons from unintended segments (accidental-overlap case, possibly in some agencies' implementation).
Expected behavior
Simulation shadow pricing should use a segment column consistent with workplace chooser segmentation and SEGMENT_IDS, or fail fast with a clear configuration error.
Fix Ideas
- Option 1: explicitly set
SEGMENT_TO_NAME in the shadow_pricing.yaml to match the workplace segment, for example, this should be set in the SANDAG example:
# map model selectors to chooser segment columns used by shadow pricing simulation
SEGMENT_TO_NAME:
school: school_segment
workplace: occupation
- Option 2: make a fix in the shadow_pricing.py source code to default
SEGMENT_TO_NAME to work and school location's model_settings.CHOOSER_SEGMENT_COLUMN_NAME so that they are consistent
I think Option 2 is the superior answer here, and should be pretty straightforward to implement.
Describe the bug
Simulation shadow pricing can use an inconsistent workplace segment column and silently resimulate the wrong persons, or no persons at all.
This is happening in the SANDAG example model, and highly likely in the SANDAG production model, and in some agencies' current ActivitySim implementation, if they use the simulation method for shadow pricing and do not segment by income. This is easy to miss because the run can continue without an exception. See the attached log file showing no choosers were resimulated in workplace location in the full size SANDAG example model run (search for workplace_location.i2).
mp_households_0-activitysim.log
With the simulation-based method, shadow pricing uses
SEGMENT_TO_NAME(defaulted toincome_segment) to choose a persons_merged segment field, then filters persons by equality with workplaceSEGMENT_IDS. If user segments the workplace location byoccupation(or another field) and does not specifySEGMENT_TO_NAMEin the shadow pricing yaml, the filter is inconsistent.This creates two failure modes:
segment_idsin the SANDAG example, vs the default numericincome_segment), so zero persons are sampled and resimulated for intended segments.Relevant code path:
income_segmentin activitysim/activitysim/abm/tables/shadow_pricing.pySEGMENT_TO_NAMEin activitysim/activitysim/abm/tables/shadow_pricing.pySEGMENT_IDSin activitysim/activitysim/abm/tables/shadow_pricing.pyTo Reproduce
Steps to reproduce the behavior:
SHADOW_PRICE_METHOD: simulation), for example sandag-abm3-example/configs/resident/shadow_pricing.yaml.occupationand occupation-basedSEGMENT_IDS, for example sandag-abm3-example/configs/resident/workplace_location.yaml.Expected behavior
Simulation shadow pricing should use a segment column consistent with workplace chooser segmentation and
SEGMENT_IDS, or fail fast with a clear configuration error.Fix Ideas
SEGMENT_TO_NAMEin the shadow_pricing.yaml to match the workplace segment, for example, this should be set in the SANDAG example:SEGMENT_TO_NAMEto work and school location'smodel_settings.CHOOSER_SEGMENT_COLUMN_NAMEso that they are consistentI think Option 2 is the superior answer here, and should be pretty straightforward to implement.