File size: 2,529 Bytes
a58f1b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# modules/trip_generation.py
# TripAI – Trip Generation Model

from __future__ import annotations
import pandas as pd
import numpy as np

PURPOSES = ["HBW", "HBE", "HBS"]


def trip_generation(taz: pd.DataFrame) -> tuple[pd.DataFrame, pd.DataFrame]:
    """

    Compute trip productions and attractions for each TAZ for three purposes:

    - HBW: Home–Based Work

    - HBE: Home–Based Education

    - HBS: Home–Based Shopping/Other



    The functional forms are deliberately simple but grounded in standard

    trip-rate logic and can be modified for calibration.



    Parameters

    ----------

    taz : pd.DataFrame

        TAZ-level attributes with at least the following columns:

        ['households', 'workers', 'students', 'cars',

         'service_jobs', 'industrial_jobs', 'retail_jobs',

         'school_capacity', 'retail_floor_area'].



    Returns

    -------

    productions : pd.DataFrame

        Index = TAZ, columns = ['HBW', 'HBE', 'HBS'].

    attractions : pd.DataFrame

        Index = TAZ, columns = ['HBW', 'HBE', 'HBS'], balanced so that

        sum(P) = sum(A) for each purpose.

    """
    df = taz.copy()

    # ------------------------------------------------
    # PRODUCTIONS (simple rate-based formulations)
    # ------------------------------------------------
    # HBW: mainly driven by workers and car availability
    P_HBW = 0.8 * df["workers"] + 0.2 * df["cars"]

    # HBE: driven by students
    P_HBE = 1.2 * df["students"]

    # HBS: driven by households (shopping, other)
    P_HBS = 0.4 * df["households"]

    productions = pd.DataFrame(
        {"HBW": P_HBW, "HBE": P_HBE, "HBS": P_HBS},
        index=df.index,
    )

    # ------------------------------------------------
    # ATTRACTIONS (jobs, schools, retail)
    # ------------------------------------------------
    A_HBW = 0.7 * df["service_jobs"] + 0.3 * df["industrial_jobs"]
    A_HBE = 1.5 * df["school_capacity"]
    A_HBS = 1.3 * df["retail_floor_area"]

    attractions = pd.DataFrame(
        {"HBW": A_HBW, "HBE": A_HBE, "HBS": A_HBS},
        index=df.index,
    )

    # ------------------------------------------------
    # SIMPLE BALANCING (one-step scaling)
    # ------------------------------------------------
    for p in PURPOSES:
        total_P = productions[p].sum()
        total_A = attractions[p].sum()
        if total_A > 0:
            attractions[p] *= total_P / total_A

    return productions, attractions