activitysim
activitysim copied to clipboard
Question on time table function
In the MTC model implementation, there is an expression
@(df.tour_count>1) & (df.tour_num == 1) & _adjacent_window_before
The term _adjacent_window_before is a temporary value that is an integer giving the size of the run of available adjacent time periods before the proposed tour start time.
I strongly suspect that the intention of this expression is to (a) interpret _adjacent_window_before as a boolean value, and return a "true" result when the first two parts are "true" and the last part is truthy (i.e. non-zero).
It occurs to me today that it might be meant to have a different Pythonic interpretation (b), such that the value is 0 if either of the first two parts are false, and the value is whatever _adjacent_window_before is (any integer) otherwise.
Unfortunately, the actual implementation as written is neither of these. The "@" symbol at the front flags ActivitySim to send this expression not through pandas.eval but through plain python eval. This results in upcasting the first two boolean values to integers and using the bitwise "&" operator, so the overall expression evaluates to 1 only when _adjacent_window_before is odd (i.e. when written in binary, has a 1 as the rightmost digit) and the other two conditions are also met.
This is obviously not the correct intention, and I have corrected the expression to be consistent with (a) in prototype_mtc, but if anyone believes that (b) is the correct version please speak up.
Note that, among known example models, this problem only occurs in prototype_mtc and its derivative models.
Hi Jeff,
I think you are referring to line 50 in the work tour scheduling model in TM1 (https://github.com/BayAreaMetro/travel-model-one/blob/master/model-files/model/TourDepartureAndDuration.xls), or similar lines in other purposes. It is filtering the utility term on whether this is the first tour scheduled in the day. If it is the first tour, it multiplies the number of free periods (method is shown below) before the alternative start period by the coefficient. The coefficients tend to be positive, so I think they are trying to account for a sufficient amount of time for sleeping and at-home activities before the start of the day for the first tour. There is another similar calculation for periods after the arrival hour of the alternative, so this has the effect of "centering" the tour somewhere in the day. Similar calculations exist for cases where the tour being scheduled is not the first tour. Note that for later time-of-day choice model implementations, this formulation was replaced with "representative" departure and arrival periods by purpose, and the utility is specified by number of periods "away" from the representative period for both departure and arrival.
So it sounds like the _adjacent_window_before variable is being calculated correctly, but maybe the term needs to be modified to get it working like it is supposed to? It is curious to me that it isn't implemented correctly because I dont see how the TOD choice model comparisons checked out compared to TM1 if the term wasn't multiplying the coefficient by the number of adjacent periods, unless the constants are explaining all of the variation in time of day.
public int getAdjWindowBeforeThisHourAlt(int alt){
int thisTourStartsHour = altStarts[alt-1];
int numAdjacentHoursAvailable = 0;
for (int i=thisTourStartsHour-1; i >= CtrampApplication.START_HOUR; i--) {
if ( person.isHourAvailable(i) )
numAdjacentHoursAvailable++;
else
break;
}
return numAdjacentHoursAvailable;
}
My conclusions:
_adjacent_window_beforeis being calculated correctly.- The expression motivating this issue is wrong, it should be
@(df.tour_count>1) * (df.tour_num == 1) * _adjacent_window_before, i.e. multiply not bitwise-and, as per theory (b) above. - Comparing the two specs (CT-RAMP and ActivitySim) it looks like maybe also there should not be the
(df.tour_count>1)term in the ActivitySim spec. I'm not sure where "'@firstTour" is defined in the CT-RAMP, but it looks like this "centering" factor in CT-RAMP is applied to the first tour regardless of whether there is a subsequent tour or not. - I can see how this happened, as the human-readable descriptive text in both CT-RAMP and ActivitySim says "adjacent window exists", which in my mind would lead logically to the "&" instead of "*" form (even though it turns out "&" is wrong here regardless)
- It seems reasonable to guess that this term can be wrong but be such a small factor in the overall scheduling model (vs tons of constants) that the model could validate fine even with the error. I'd need to study this more to figure if that's the case here or if its something else.
firsttour is set to 1 if the tour being scheduled is the first tour scheduled out of all tours. I believe that subsequenttour in ctramp is set to 1 if firsttour==0. I think your proposed code fix is correct.