Skip to content

Standardize locals_dict contract across ABM components (shared helper functions like person_max_window) #1079

@i-am-sijia

Description

@i-am-sijia

Is your feature request related to a problem? Please describe.
I would like to estimate the non-mandatory tour destination model with person's max remaining available time window as an explanatory variable (e.g. person_max_window) but this helper function is not available in the locals_dict for that component. This is a common issue across ABM components: the locals_dict passed into components is inconsistent (sometimes empty {}, sometimes constants, sometimes richer helper dictionaries). This creates a portability and maintenance problem: expressions that work in one component can fail in another because expected helper functions are missing. It also makes review and debugging harder because there is no clear baseline contract for what locals_dict are always available.

Evidence

  1. non_mandatory_tour_frequency injects time window helpers into preprocessor locals:
    activitysim/activitysim/abm/models/non_mandatory_tour_frequency.py
  2. non_mandatory_tour_destination does not expose that same helper set at component level:
    activitysim/activitysim/abm/models/non_mandatory_destination.py
  3. Destination preprocessing locals are assembled ad hoc inside shared utility:
    activitysim/activitysim/abm/models/util/tour_destination.py
    activitysim/activitysim/abm/models/util/tour_destination.py
  4. Core APIs are flexible but do not enforce a common locals contract:
    activitysim/activitysim/core/expressions.py
    activitysim/activitysim/core/expressions.py
    activitysim/activitysim/core/simulate.py
    activitysim/activitysim/core/interaction_simulate.py

Describe the solution you'd like
Introduce and document a standardized locals_dict construction pattern for ABM components.

Proposed behavior:

  1. Build one locals_dict per model step from a shared helper/builder.
  2. Add standard helper functions (for example overlap/timetable helpers such as person_max_window and person_available_periods) where appropriate.
  3. Add model-specific extras explicitly.
  4. Reuse that same locals_dict` consistently in:
  • expressions.annotate_preprocessors
  • simple_simulate / interaction_simulate
  • expressions.annotate_tables

This should be done as a consistency refactor, with no intended behavior changes.

Describe alternatives you've considered

  1. Keep current per-component ad hoc locals_dict definitions and add missing helpers only when needed.

    • Pros: minimal immediate work. I only need to add it to the tour_destination.py for now for my specific use case.
    • Cons: code base diversions and another similar use case may arise very soon, e.g., joint tour frequency and destination.
  2. Define a global/shared locals builder and migrate.

    • Pros: clear contract, better portability, easier maintenance.
    • Cons: moderate one-time refactor effort.

Additional context
Add any other context or screenshots about the feature request here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions