Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3d4e764
Added new exceptions based on RuntimeError inventory results
JoeJimFlood Oct 8, 2025
962cd60
Changed RuntimeErrors in abm\models
JoeJimFlood Oct 8, 2025
8a58872
Corrected name of SystemConfigurationError
JoeJimFlood Oct 8, 2025
07fb9e6
Updated RuntimeErrors in abm\tables
JoeJimFlood Oct 8, 2025
dc60c38
Added SubprocessError
JoeJimFlood Oct 8, 2025
182a8cf
Updated RuntimeErrors in core directory
JoeJimFlood Oct 8, 2025
aa78a07
Renamed `TableSliceError` to `TableSlicingError`
JoeJimFlood Oct 8, 2025
a9d57a2
Classified RuntimeErrors in input and settings checkers as ModelConfi…
JoeJimFlood Oct 8, 2025
c44d071
Created `SegmentedSpecificationError` for when there's an issue with …
JoeJimFlood Oct 8, 2025
92951cf
Added TableIndexError
JoeJimFlood Oct 13, 2025
0dadec1
Classified RuntimeError in initialize_tours as InputPopulationError
JoeJimFlood Oct 13, 2025
ce0cb70
Created EstimationDataError
JoeJimFlood Oct 13, 2025
11d0c10
Improved clarity of a couple error messages
JoeJimFlood Oct 14, 2025
faa3a5b
Blacken code
JoeJimFlood Oct 14, 2025
e31a231
Updated code to reflect older version of Black (22.12.0)
JoeJimFlood Oct 14, 2025
61e1d11
Updated error messages to look for in activitysim.core tests
JoeJimFlood Oct 15, 2025
2e127ef
Updated error to look for in abm.text
JoeJimFlood Oct 15, 2025
dde2b6f
Changed SystemConfigurationError to TableSlicingError in test
JoeJimFlood Oct 15, 2025
e1ee193
Reclasified error when a step is run more than once from TableSlicing…
JoeJimFlood Oct 15, 2025
542c3ae
Renamed InputPopulationError to InputTableError for clarity as it can…
JoeJimFlood Oct 15, 2025
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
8 changes: 5 additions & 3 deletions activitysim/abm/models/disaggregate_accessibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,9 +622,11 @@ def create_proto_pop(self):

# Create ID columns, defaults to "%tablename%_id"
hhid, perid, tourid = (
self.params[x]["index_col"]
if len(self.params[x]["index_col"]) > 0
else x + "_id"
(
self.params[x]["index_col"]
if len(self.params[x]["index_col"]) > 0
else x + "_id"
)
for x in klist
)

Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/models/initialize_tours.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from activitysim.core import expressions, tracing, workflow
from activitysim.core.configuration import PydanticReadable
from activitysim.core.configuration.base import PreprocessorSettings
from activitysim.core.exceptions import InputTableError
from activitysim.core.input import read_input_table

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -140,7 +141,7 @@ def initialize_tours(
f"{tours_without_persons.sum()} tours out of {len(persons)} without persons\n"
f"{pd.Series({'person_id': tours_without_persons.index.values})}"
)
raise RuntimeError(f"{tours_without_persons.sum()} tours with bad person_id")
raise InputTableError(f"{tours_without_persons.sum()} tours with bad person_id")

if trace_hh_id:
state.tracing.trace_df(tours, label="initialize_tours", warn_if_empty=True)
3 changes: 2 additions & 1 deletion activitysim/abm/models/input_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from activitysim.core import workflow
from activitysim.core.input import read_input_table
from activitysim.core.exceptions import ModelConfigurationError

logger = logging.getLogger(__name__)
file_logger = logger.getChild("logfile")
Expand Down Expand Up @@ -468,6 +469,6 @@ def input_checker(state: workflow.State):

if input_check_failure:
logger.error("Run is killed due to input checker failure!!")
raise RuntimeError(
raise ModelConfigurationError(
"Encountered error in input checker, see input_checker.log for details"
)
5 changes: 3 additions & 2 deletions activitysim/abm/models/joint_tour_participation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from activitysim.core.configuration.base import ComputeSettings, PreprocessorSettings
from activitysim.core.configuration.logit import LogitComponentSettings
from activitysim.core.util import assign_in_place, reindex
from activitysim.core.exceptions import InvalidTravelError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -218,11 +219,11 @@ def participants_chooser(
non_choice_col = [col for col in probs.columns if col != choice_col][0]
probs[non_choice_col] = 1 - probs[choice_col]
if iter > MAX_ITERATIONS + 1:
raise RuntimeError(
raise InvalidTravelError(
f"{num_tours_remaining} tours could not be satisfied even with forcing participation"
)
else:
raise RuntimeError(
raise InvalidTravelError(
f"{num_tours_remaining} tours could not be satisfied after {iter} iterations"
)

Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/models/location_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from activitysim.core.interaction_sample import interaction_sample
from activitysim.core.interaction_sample_simulate import interaction_sample_simulate
from activitysim.core.util import reindex
from activitysim.core.exceptions import DuplicateWorkflowTableError

"""
The school/workplace location model predicts the zones in which various people will
Expand Down Expand Up @@ -1125,7 +1126,7 @@ def iterate_location_choice(
assert len(save_sample_df.index.get_level_values(0).unique()) == len(choices_df)
# lest they try to put school and workplace samples into the same table
if state.is_table(sample_table_name):
raise RuntimeError(
raise DuplicateWorkflowTableError(
"dest choice sample table %s already exists" % sample_table_name
)
state.extend_table(sample_table_name, save_sample_df)
Expand Down
5 changes: 4 additions & 1 deletion activitysim/abm/models/parking_location_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from activitysim.core.interaction_sample_simulate import interaction_sample_simulate
from activitysim.core.tracing import print_elapsed_time
from activitysim.core.util import assign_in_place, drop_unused_columns
from activitysim.core.exceptions import DuplicateWorkflowTableError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -500,7 +501,9 @@ def parking_location(

# lest they try to put tour samples into the same table
if state.is_table(sample_table_name):
raise RuntimeError("sample table %s already exists" % sample_table_name)
raise DuplicateWorkflowTableError(
"sample table %s already exists" % sample_table_name
)
state.extend_table(sample_table_name, save_sample_df)

expressions.annotate_tables(
Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/models/settings_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
eval_nest_coefficients,
read_model_coefficient_template,
)
from activitysim.core.exceptions import ModelConfigurationError

# import model settings
from activitysim.abm.models.accessibility import AccessibilitySettings
Expand Down Expand Up @@ -760,7 +761,7 @@ def check_model_settings(
for e in all_errors:
logger.error(f"\t{str(e)}")
file_logger.error(f"\t{str(e)}")
raise RuntimeError(
raise ModelConfigurationError(
f"Encountered one or more errors in settings checker. See f{log_file} for details."
)
msg = f"Setting Checker Complete. No runtime errors were raised. Check f{log_file} for warnings. These *may* prevent model from successfully running."
Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/models/trip_departure_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from activitysim.core.skim_dataset import SkimDataset
from activitysim.core.skim_dictionary import SkimDict
from activitysim.core.util import reindex
from activitysim.core.exceptions import SegmentedSpecificationError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -219,7 +220,7 @@ def choose_tour_leg_pattern(
)

if len(spec.columns) > 1:
raise RuntimeError("spec must have only one column")
raise SegmentedSpecificationError("spec must have only one column")

# - join choosers and alts
# in vanilla interaction_simulate interaction_df is cross join of choosers and alternatives
Expand Down
7 changes: 5 additions & 2 deletions activitysim/abm/models/trip_destination.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from activitysim.core.skim_dictionary import DataFrameMatrix
from activitysim.core.tracing import print_elapsed_time
from activitysim.core.util import assign_in_place, reindex
from activitysim.core.exceptions import InvalidTravelError, DuplicateWorkflowTableError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -1664,7 +1665,7 @@ def trip_destination(
# testing feature t0 make sure at least one trip fails so trip_purpose_and_destination model is run
if state.settings.testing_fail_trip_destination and not trips_df.failed.any():
if (trips_df.trip_num < trips_df.trip_count).sum() == 0:
raise RuntimeError(
raise InvalidTravelError(
"can't honor 'testing_fail_trip_destination' setting because no intermediate trips"
)

Expand Down Expand Up @@ -1745,7 +1746,9 @@ def trip_destination(

# lest they try to put tour samples into the same table
if state.is_table(sample_table_name):
raise RuntimeError("sample table %s already exists" % sample_table_name)
raise DuplicateWorkflowTableError(
"sample table %s already exists" % sample_table_name
)
state.extend_table(sample_table_name, save_sample_df)

expressions.annotate_tables(
Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/models/trip_purpose.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
)
from activitysim.core.configuration.base import PreprocessorSettings, PydanticReadable
from activitysim.core.util import reindex
from activitysim.core.exceptions import InvalidTravelError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -134,7 +135,7 @@ def choose_intermediate_trip_purpose(
state.tracing.write_csv(
unmatched_choosers, file_name=file_name, transpose=False
)
raise RuntimeError(
raise InvalidTravelError(
"Some trips could not be matched to probs based on join columns %s."
% probs_join_cols
)
Expand Down
15 changes: 10 additions & 5 deletions activitysim/abm/models/trip_scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from activitysim.core import chunk, config, estimation, expressions, tracing, workflow
from activitysim.core.configuration.base import PreprocessorSettings, PydanticReadable
from activitysim.core.util import reindex
from activitysim.core.exceptions import InvalidTravelError, PipelineError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -584,9 +585,11 @@ def trip_scheduling(
i = 0
while (i < max_iterations) and not trips_chunk.empty:
# only chunk log first iteration since memory use declines with each iteration
with chunk.chunk_log(
state, trace_label
) if i == 0 else chunk.chunk_log_skip():
with (
chunk.chunk_log(state, trace_label)
if i == 0
else chunk.chunk_log_skip()
):
i += 1
is_last_iteration = i == max_iterations

Expand Down Expand Up @@ -615,7 +618,9 @@ def trip_scheduling(
logger.info("%s %s failed", trace_label_i, failed.sum())

if (failed.sum() > 0) & (model_settings.scheduling_mode == "relative"):
raise RuntimeError("failed trips with relative scheduling mode")
raise InvalidTravelError(
"failed trips with relative scheduling mode"
)

if not is_last_iteration:
# boolean series of trips whose leg scheduling failed
Expand Down Expand Up @@ -653,7 +658,7 @@ def trip_scheduling(
)

if failfix != FAILFIX_DROP_AND_CLEANUP:
raise RuntimeError(
raise PipelineError(
"%s setting '%s' not enabled in settings"
% (FAILFIX, FAILFIX_DROP_AND_CLEANUP)
)
Expand Down
10 changes: 6 additions & 4 deletions activitysim/abm/models/util/cdap.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from activitysim.core import chunk, logit, simulate, tracing, workflow
from activitysim.core.configuration.base import ComputeSettings
from activitysim.core.exceptions import ModelConfigurationError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,7 +49,7 @@ def add_pn(col, pnum):
elif isinstance(col, (list, tuple)):
return [c if c == _hh_id_ else "%s_p%s" % (c, pnum) for c in col]
else:
raise RuntimeError("add_pn col not list or str")
raise TypeError("add_pn col not list or str")


def assign_cdap_rank(
Expand Down Expand Up @@ -270,7 +271,7 @@ def preprocess_interaction_coefficients(interaction_coefficients):
"Error in cdap_interaction_coefficients at row %s. Expect only M, N, or H!"
% coefficients[~coefficients["activity"].isin(["M", "N", "H"])].index.values
)
raise RuntimeError(msg)
raise ModelConfigurationError(msg)

coefficients["cardinality"] = (
coefficients["interaction_ptypes"].astype(str).str.len()
Expand Down Expand Up @@ -470,8 +471,9 @@ def build_cdap_spec(
continue

if not (0 <= row.cardinality <= MAX_INTERACTION_CARDINALITY):
raise RuntimeError(
"Bad row cardinality %d for %s" % (row.cardinality, row.slug)
raise ModelConfigurationError(
"Bad row cardinality %d for %s. Try checking that all interaction terms include 3 or fewer person types."
% (row.cardinality, row.slug)
)

# for all other interaction rules, we need to generate a row in the spec for each
Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/models/util/probabilistic_scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pandas as pd

from activitysim.core import chunk, logit, tracing, workflow
from activitysim.core.exceptions import InvalidTravelError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -210,7 +211,7 @@ def _postprocess_scheduling_choices(

if scheduling_mode == "relative":
if failed.any():
RuntimeError(
InvalidTravelError(
f"Failed trips in realtive mode for {failed.sum()} trips: {choosers[failed]}"
)

Expand Down
2 changes: 1 addition & 1 deletion activitysim/abm/models/util/vectorize_tour_scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def skims_for_logsums(
elif isinstance(destination_for_tour_purpose, dict):
dest_col_name = destination_for_tour_purpose.get(tour_purpose)
else:
raise RuntimeError(
raise TypeError(
f"expected string or dict DESTINATION_FOR_TOUR_PURPOSE model_setting for {tour_purpose}"
)

Expand Down
3 changes: 2 additions & 1 deletion activitysim/abm/tables/households.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from activitysim.abm.tables.util import simple_table_join
from activitysim.core import tracing, workflow
from activitysim.core.input import read_input_table
from activitysim.core.exceptions import MissingInputTableDefinition

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,7 +46,7 @@ def households(state: workflow.State) -> pd.DataFrame:
)

if df.shape[0] == 0:
raise RuntimeError("No override households found in store")
raise MissingInputTableDefinition("No override households found in store")

# if we are tracing hh exclusively
elif _trace_hh_id and households_sample_size == 1:
Expand Down
7 changes: 4 additions & 3 deletions activitysim/abm/tables/persons.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from activitysim.abm.tables.util import simple_table_join
from activitysim.core import workflow
from activitysim.core.exceptions import InputTableError
from activitysim.core.input import read_input_table

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -55,7 +56,7 @@ def persons(state: workflow.State) -> pd.DataFrame:
f"{persons_without_households.sum()} persons out of {len(df)} without households\n"
f"{pd.Series({'person_id': persons_without_households.index.values})}"
)
raise RuntimeError(
raise InputTableError(
f"{persons_without_households.sum()} persons with bad household_id"
)

Expand All @@ -67,7 +68,7 @@ def persons(state: workflow.State) -> pd.DataFrame:
f"{households_without_persons.sum()} households out of {len(households.index)} without persons\n"
f"{pd.Series({'household_id': households_without_persons.index.values})}"
)
raise RuntimeError(
raise InputTableError(
f"{households_without_persons.sum()} households with no persons"
)

Expand Down Expand Up @@ -107,5 +108,5 @@ def persons_merged(
left_on="person_id",
)
if n_persons != len(persons):
raise RuntimeError("number of persons changed")
raise InputTableError("number of persons changed")
return persons
Loading