From 08b30c7679b3c094bb751a4ca67b436f31951b86 Mon Sep 17 00:00:00 2001 From: David Hensle Date: Tue, 21 Mar 2023 15:42:48 -0700 Subject: [PATCH 1/4] avoid infinite loop if forcing does not work --- activitysim/abm/models/joint_tour_participation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/activitysim/abm/models/joint_tour_participation.py b/activitysim/abm/models/joint_tour_participation.py index ee8658ae5f..d079322e6e 100644 --- a/activitysim/abm/models/joint_tour_participation.py +++ b/activitysim/abm/models/joint_tour_participation.py @@ -209,6 +209,10 @@ def participants_chooser(probs, choosers, spec, trace_label): probs[choice_col] = np.where(probs[choice_col] > 0, 1, 0) 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( + f"{num_tours_remaining} tours could not be satisfied even with forcing participation" + ) else: raise RuntimeError( f"{num_tours_remaining} tours could not be satisfied after {iter} iterations" From a732ee6e51b019cefa5d4254096aa514271dfd80 Mon Sep 17 00:00:00 2001 From: David Hensle Date: Thu, 30 Mar 2023 16:05:34 -0700 Subject: [PATCH 2/4] better error message --- activitysim/abm/models/joint_tour_participation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/activitysim/abm/models/joint_tour_participation.py b/activitysim/abm/models/joint_tour_participation.py index d079322e6e..5032fe49b7 100644 --- a/activitysim/abm/models/joint_tour_participation.py +++ b/activitysim/abm/models/joint_tour_participation.py @@ -211,7 +211,10 @@ def participants_chooser(probs, choosers, spec, trace_label): probs[non_choice_col] = 1 - probs[choice_col] if iter > MAX_ITERATIONS + 1: raise RuntimeError( - f"{num_tours_remaining} tours could not be satisfied even with forcing participation" + f"{num_tours_remaining} tours could not be satisfied even with forcing participation." + " This is likely due to some inconsistency between the tour frequency & composition model" + " and the joint tour participation model, e.g. overlapping time windows with mandatory tours." + " It could also be inconsistencies in the data if run in estimation mode." ) else: raise RuntimeError( From ccbdc6d3a68dc465d84892af9a33808dcb40fbdd Mon Sep 17 00:00:00 2001 From: David Hensle Date: Thu, 30 Mar 2023 16:11:25 -0700 Subject: [PATCH 3/4] formatting --- activitysim/abm/models/joint_tour_participation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activitysim/abm/models/joint_tour_participation.py b/activitysim/abm/models/joint_tour_participation.py index 5032fe49b7..ea6d77ebb3 100644 --- a/activitysim/abm/models/joint_tour_participation.py +++ b/activitysim/abm/models/joint_tour_participation.py @@ -211,8 +211,8 @@ def participants_chooser(probs, choosers, spec, trace_label): probs[non_choice_col] = 1 - probs[choice_col] if iter > MAX_ITERATIONS + 1: raise RuntimeError( - f"{num_tours_remaining} tours could not be satisfied even with forcing participation." - " This is likely due to some inconsistency between the tour frequency & composition model" + f"{num_tours_remaining} tours could not be satisfied even with forcing participation." + " This is likely due to some inconsistency between the tour frequency & composition model" " and the joint tour participation model, e.g. overlapping time windows with mandatory tours." " It could also be inconsistencies in the data if run in estimation mode." ) From 9b34aae39033640bd11c70d8c8d346372813063d Mon Sep 17 00:00:00 2001 From: David Hensle Date: Wed, 26 Jul 2023 22:34:05 -0700 Subject: [PATCH 4/4] additional documentation --- activitysim/abm/models/joint_tour_participation.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/activitysim/abm/models/joint_tour_participation.py b/activitysim/abm/models/joint_tour_participation.py index ea6d77ebb3..bc98e13f92 100644 --- a/activitysim/abm/models/joint_tour_participation.py +++ b/activitysim/abm/models/joint_tour_participation.py @@ -132,8 +132,12 @@ def participants_chooser(probs, choosers, spec, trace_label): and then check to see if the tour statisfies this requirement, and rechoose for any that fail until all are satisfied. - In principal, this shold always occur eventually, but we fail after MAX_ITERATIONS, - just in case there is some failure in program logic (haven't seen this occur.) + In principal, this shold always occur eventually, but we fail after MAX_ITERATIONS. + Failure can happen due to sampling on really small probabilities of participation for + household members. There is an optional setting to force participation of all household + members with non-zero probability after MAX_ITERATIONS. Even with this forced participation, + tours can still be unsatisfied due to logical consistencies in upstream models or bad input + data in estimation mode. If forced participation does not work, the run will crash. The return values are the same as logit.make_choices