Skip to content

Commit db03dae

Browse files
authored
Merge pull request #11 from camsys/data-type-op-pd-cat
latest updates from other PRs
2 parents a3cb622 + 1f40c06 commit db03dae

29 files changed

+827
-630
lines changed

.github/workflows/core_tests.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
mamba env update -n asim-test -f conda-environments/github-actions-tests.yml
5050
mamba install --yes \
5151
"psutil=5.9.5" \
52-
"pydantic=1.10.13" \
52+
"pydantic=2.6.1" \
5353
"pypyr=5.8.0" \
5454
"pytables=3.6.1" \
5555
"pytest-cov" \
@@ -149,7 +149,7 @@ jobs:
149149
mamba env update -n asim-test -f conda-environments/github-actions-tests.yml
150150
mamba install --yes \
151151
"psutil=5.9.5" \
152-
"pydantic=1.10.13" \
152+
"pydantic=2.6.1" \
153153
"pypyr=5.8.0" \
154154
"pytables=3.6.1" \
155155
"pytest-cov" \
@@ -247,7 +247,7 @@ jobs:
247247
mamba env update -n asim-test -f conda-environments/github-actions-tests.yml
248248
mamba install --yes \
249249
"psutil=5.9.5" \
250-
"pydantic=1.10.13" \
250+
"pydantic=2.6.1" \
251251
"pypyr=5.8.0" \
252252
"pytables=3.6.1" \
253253
"pytest-cov" \
@@ -344,7 +344,7 @@ jobs:
344344
mamba env update -n asim-test -f conda-environments/github-actions-tests.yml
345345
mamba install --yes \
346346
"psutil=5.9.5" \
347-
"pydantic=1.10.13" \
347+
"pydantic=2.6.1" \
348348
"pypyr=5.8.0" \
349349
"pytables=3.6.1" \
350350
"pytest-cov" \
@@ -411,7 +411,7 @@ jobs:
411411
mamba env update -n asim-test -f conda-environments/github-actions-tests.yml
412412
mamba install --yes \
413413
"psutil=5.9.5" \
414-
"pydantic=1.10.13" \
414+
"pydantic=2.6.1" \
415415
"pypyr=5.8.0" \
416416
"pytables=3.6.1" \
417417
"pytest-cov" \
@@ -477,7 +477,7 @@ jobs:
477477
mamba env update -n asim-test -f conda-environments/github-actions-tests.yml
478478
mamba install --yes \
479479
"psutil=5.9.5" \
480-
"pydantic=1.10.13" \
480+
"pydantic=2.6.1" \
481481
"pypyr=5.8.0" \
482482
"pytables=3.6.1" \
483483
"pytest-cov" \

activitysim/abm/models/non_mandatory_tour_frequency.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import logging
6+
import warnings
67
from pathlib import Path
78
from typing import Any
89

@@ -200,12 +201,24 @@ def non_mandatory_tour_frequency(
200201
model_settings_file_name,
201202
)
202203

203-
# FIXME kind of tacky both that we know to add this here and del it below
204-
# 'tot_tours' is used in model_spec expressions
205204
alternatives = simulate.read_model_alts(
206205
state, "non_mandatory_tour_frequency_alternatives.csv", set_index=None
207206
)
208-
alternatives["tot_tours"] = alternatives.sum(axis=1)
207+
if "tot_tours" not in alternatives.columns:
208+
# add a column for total tours
209+
alternatives["tot_tours"] = alternatives.sum(axis=1)
210+
warnings.warn(
211+
"The 'tot_tours' column may not be automatically added in the future.",
212+
FutureWarning,
213+
)
214+
else:
215+
# tot_tours already exists, check if it is consistent with legacy behavior
216+
if not (alternatives["tot_tours"] == alternatives.sum(axis=1)).all():
217+
warnings.warn(
218+
"The 'tot_tours' column in non_mandatory_tour_frequency_alternatives.csv "
219+
"does not match the sum of the other columns.",
220+
RuntimeWarning,
221+
)
209222

210223
# filter based on results of CDAP
211224
choosers = persons_merged

activitysim/abm/models/util/canonical_ids.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def determine_flavors_from_alts_file(
182182
flavors = {
183183
c: int(alts[c].max() + max_extension)
184184
for c in alts.columns
185-
if all(alts[c].astype(str).str.isnumeric())
185+
if all(alts[c].astype(str).str.isnumeric()) and (c != "tot_tours")
186186
}
187187
valid_flavors = all(
188188
[(isinstance(flavor, str) & (num >= 0)) for flavor, num in flavors.items()]

activitysim/abm/models/util/logsums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ def compute_location_choice_logsums(
8484
computed logsums with same index as choosers
8585
"""
8686
if isinstance(model_settings, dict):
87-
model_settings = TourLocationComponentSettings.parse_obj(model_settings)
87+
model_settings = TourLocationComponentSettings.model_validate(model_settings)
8888
if isinstance(logsum_settings, dict):
89-
logsum_settings = TourModeComponentSettings.parse_obj(logsum_settings)
89+
logsum_settings = TourModeComponentSettings.model_validate(logsum_settings)
9090

9191
trace_label = tracing.extend_trace_label(trace_label, "compute_logsums")
9292
logger.debug(f"Running compute_logsums with {choosers.shape[0]:d} choosers")
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# ActivitySim
2+
# See full license in LICENSE.txt.
3+
4+
import pandas as pd
5+
import pandas.testing as pdt
6+
7+
from activitysim.abm.models.vehicle_type_choice import (
8+
get_combinatorial_vehicle_alternatives,
9+
construct_model_alternatives,
10+
VehicleTypeChoiceSettings,
11+
)
12+
from activitysim.core import workflow
13+
14+
15+
def test_vehicle_type_alts():
16+
state = workflow.State.make_default(__file__)
17+
18+
alts_cats_dict = {
19+
"body_type": ["Car", "SUV"],
20+
"fuel_type": ["Gas", "BEV"],
21+
"age": [1, 2, 3],
22+
}
23+
24+
alts_wide, alts_long = get_combinatorial_vehicle_alternatives(alts_cats_dict)
25+
26+
# alts are initially constructed combinatorially
27+
assert len(alts_long) == 12, "alts_long should have 12 rows"
28+
assert len(alts_wide) == 12, "alts_wide should have 12 rows"
29+
30+
model_settings = VehicleTypeChoiceSettings.model_construct()
31+
model_settings.combinatorial_alts = alts_cats_dict
32+
model_settings.PROBS_SPEC = None
33+
model_settings.WRITE_OUT_ALTS_FILE = False
34+
35+
# constructing veh type data with missing alts
36+
vehicle_type_data = pd.DataFrame(
37+
data={
38+
"body_type": ["Car", "Car", "Car", "SUV", "SUV"],
39+
"fuel_type": ["Gas", "Gas", "BEV", "Gas", "BEV"],
40+
"age": ["1", "2", "3", "1", "2"],
41+
"dummy_data": [1, 2, 3, 4, 5],
42+
},
43+
index=[0, 1, 2, 3, 4],
44+
)
45+
46+
alts_wide, alts_long = construct_model_alternatives(
47+
state, model_settings, alts_cats_dict, vehicle_type_data
48+
)
49+
50+
# should only have alts left that are in the file
51+
assert len(alts_long) == 5, "alts_long should have 5 rows"
52+
53+
# indexes need to be the same to choices match alts
54+
pdt.assert_index_equal(alts_long.index, alts_wide.index)
55+
56+
# columns need to be in correct order for downstream configs
57+
pdt.assert_index_equal(
58+
alts_long.columns, pd.Index(["body_type", "age", "fuel_type"])
59+
)

activitysim/abm/models/vehicle_type_choice.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,19 @@ def construct_model_alternatives(
244244
), f"missing vehicle data for alternatives:\n {missing_alts}"
245245
else:
246246
# eliminate alternatives if no vehicle type data
247-
# if this happens, alts_wide is not the same length as alts_long
247+
num_alts_before_filer = len(alts_wide)
248248
alts_wide = alts_wide[alts_wide._merge != "left_only"]
249+
logger.warning(
250+
f"Removed {num_alts_before_filer - len(alts_wide)} alternatives not included in input vehicle type data."
251+
)
252+
# need to also remove any alts from alts_long
253+
alts_long.set_index(["body_type", "age", "fuel_type"], inplace=True)
254+
alts_long = alts_long[
255+
alts_long.index.isin(
256+
alts_wide.set_index(["body_type", "age", "fuel_type"]).index
257+
)
258+
].reset_index()
259+
alts_long.index = alts_wide.index
249260
alts_wide.drop(columns="_merge", inplace=True)
250261

251262
# converting age to integer to allow interactions in utilities
@@ -481,11 +492,11 @@ def iterate_vehicle_type_choice(
481492
alts = (
482493
alts_long[alts_long.columns]
483494
.apply(lambda row: "_".join(row.values.astype(str)), axis=1)
484-
.values
495+
.to_dict()
485496
)
486497
else:
487-
alts = model_spec.columns
488-
choices["vehicle_type"] = choices["vehicle_type"].map(dict(enumerate(alts)))
498+
alts = enumerate(dict(model_spec.columns))
499+
choices["vehicle_type"] = choices["vehicle_type"].map(alts)
489500

490501
# STEP II: append probabilistic vehicle type attributes
491502
if probs_spec_file is not None:

activitysim/abm/tables/shadow_pricing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ def load_shadow_price_calculator(
12331233
spc : ShadowPriceCalculator
12341234
"""
12351235
if not isinstance(model_settings, TourLocationComponentSettings):
1236-
model_settings = TourLocationComponentSettings.parse_obj(model_settings)
1236+
model_settings = TourLocationComponentSettings.model_validate(model_settings)
12371237

12381238
num_processes = state.get_injectable("num_processes", 1)
12391239

activitysim/abm/test/test_misc/test_load_cached_accessibility.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def test_load_cached_accessibility():
5858
settings = state.settings
5959
input_table_list = settings.input_table_list
6060
input_table_list.append(
61-
configuration.InputTable.parse_obj(
61+
configuration.InputTable.model_validate(
6262
{
6363
"tablename": "accessibility",
6464
"filename": "cached_accessibility.csv",

activitysim/core/configuration/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class PreprocessorSettings(PydanticBase):
118118
The preprocessor will emit rows to a temporary table that match the rows
119119
in this table from the pipeline."""
120120

121-
TABLES: list[str] | None
121+
TABLES: list[str] | None = None
122122
"""Names of the additional tables to be merged for the preprocessor.
123123
124124
Data from these tables will be merged into the primary table, according

activitysim/core/configuration/filesystem.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ def read_settings_file(
639639
include_stack: bool = False,
640640
configs_dir_list: tuple[Path] | None = None,
641641
validator_class: type[PydanticBase] | None = None,
642-
) -> dict | PydanticBase:
642+
) -> PydanticBase | dict:
643643
"""
644644
Load settings from one or more yaml files.
645645
@@ -817,7 +817,7 @@ def backfill_settings(settings, backfill):
817817
settings.pop("include_settings", None)
818818

819819
if validator_class is not None:
820-
settings = validator_class.parse_obj(settings)
820+
settings = validator_class.model_validate(settings)
821821

822822
if include_stack:
823823
# if we were called recursively, return an updated list of source_file_paths

0 commit comments

Comments
 (0)