Unreasonably high travel speeds in simulation results
Closed this issue · 8 comments
I'm maintaining a parcel demand model, that uses MATSim for traffic assignment.
I ran a few simulations and upon further analysis of the results, I discovered strange spikes in the travel speeds.
Debugging reveals the maxVelocity
of the vehicle and the link freespeed
of the network are ignored during routing, leading to unreasonable spikes in travel speed.
Below is a chart showing the distribution of travel speed on the network for a small sample. The maxVelocity
of the truck in this case is set to 150km/h (42m/s) and the freespeed
is 45 km/h (12.5m/s) on majority of the links.
The spikes are even more pronounced in larger samples like the one below, with speeds reaching as high as 1200km/h.
I suspect this might have something to do with an incorrectly configured parameter in the config file but I can’t seem to pin down the issue.
I created a GitHub repo containing the config file
, plans file
, vehicles file
and the network file
for the small sample data
GitHub: speedspike-issue-v14
Please can you point me to where I should look for a solution @rewertvsp
Dear Ibraheem, please take a look at my answer by email. There should be some hints for taking a more in-depth look into it.
In general, it would be very nice to avoid this double posting: GH issue (usually good!) and parallel same-wording e-mail — without link to the GH Issue — to another person. This causes unnecessary double-work. Thanks a lot!
And please report back here, when you find out a bit more.
Hi @kt86,
Thank you for your response via email. The pointers were very helpful for further investigation.
Also, I apologize for the double posting, I would make sure to avoid that next time.
I have some updates regarding this issue.
Contrary to my initial thoughts, the issue wasn't related to the config
nor the router ignoring the vehicle's maxVelocity
and link freespeed
during routing. It also wasn't as a result of the inclusion of network mode bike
because the issue persists when a single vehicleType
and network mode car
is used.
The issue appears to be related to how the distance of a route
is calculated in MATSim and by extension the required travelTime
for traversing the route.
Following your pointers, I decided to run a simulation with only one vehicle type car
and I was able to replicate the issue. I also further reduced the sample data and the spike was narrowed to a single datapoint exceeding the maxVelocity
of the vehicle (151.2km/h -- 42m/s).
I looked into the single datapoint and I was able to find the
leg
, and it's correspondingroute
within theplan file
.
The travel time here is 3 seconds and the distance is ~164m. The speed here would be 54.67m/s -- 196.8km/h.
<leg mode="car" dep_time="08:58:07" trav_time="00:00:03">
<attributes>
<attribute name="routingMode" class="java.lang.String">car</attribute>
</attributes>
<route type="links" start_link="1141076970002f" end_link="1379264710003f" trav_time="00:00:03" distance="164.05003954068263" vehicleRefId="Dr4|0|0_car">1141076970002f 92528380001f 8129844180000f 1379264710003f</route>
</leg>
These are the four traversed
links
for theleg
(extracted from thenetwork
)
<link id="1141076970002f" from="4209129467" to="84839649" length="42.76680076599318" freespeed="12.5" capacity="1200.0" permlanes="1.0" oneway="1" modes="bike,car" type="tertiary" />
<link id="92528380001f" from="84839649" to="81662342" length="18.686648650087104" freespeed="12.5" capacity="1200.0" permlanes="1.0" oneway="1" modes="bike,car" type="tertiary" />
<link id="8129844180000f" from="81662342" to="1574193799" length="23.29933698129051" freespeed="12.5" capacity="1200.0" permlanes="1.0" oneway="1" modes="bike,car" type="tertiary" />
<link id="1379264710003f" from="1574193799" to="276025086" length="122.064053909305" freespeed="12.5" capacity="600.0" permlanes="1.0" oneway="1" modes="bike,car" type="tertiary" />
Below is an analysis of the
leg
travel time and distance.
The cells highlighted green is the result obtained fromleg.getTravelTime().seconds()
andleg.getRoute().getDistance()
. These values also match the leg distance in the snippet of the outputplan file
above. It seems the computation for the distance of aleg
includes the length of the destinationlink
but the travel time calculation excludes the destinationlink
.
I believe this inconsistency is the reason for the strange spikes in travel speeds.
A few additional details:
- The relevant MATSim version here is v14.0. So it makes sense to ask if this has been picked up and resolved in a later version.
- I performed a similar analysis on simulation results from an older version of MATSim (v7) and the calculation for both travel time and distance exclude the
origin
anddestination
links. So, this behaviour wasn't always the case.
I traced the source of this behavior and it's from a method RouteUtils.calcDistance()
in matsim-org: RouteUtils.calcRoute()
In the code block below, Line 170 adds the travelled distance on the endLink
to the route distance, if the startLink
and endLink
are not the same. Correspondingly, line 173 deducts the distance not travelled on the endLink
from the route distance, if start and end links are the same.
Since, for each leg, MATSim agents typically enter and leave traffic at a link’s end, I assume this was implemented to consider the entire distance travelled for the route, which should include the endLink
. I believe this is correctly implemented.
163 public static double calcDistance(final NetworkRoute networkRoute, final double relPosOnDepartureLink, final double relPosOnArrivalLink, final Network network) {
164 // sum distance of all link besides departure and arrival link
165 double routeDistance = calcDistanceExcludingStartEndLink(networkRoute, network);
166 // add relative distance of departure link
167 routeDistance += network.getLinks().get(networkRoute.getStartLinkId()).getLength() * (1.0 - relPosOnDepartureLink);
168 if (!networkRoute.getStartLinkId().equals(networkRoute.getEndLinkId())){
169 // add relative distance of arrival link
170 routeDistance += network.getLinks().get(networkRoute.getEndLinkId()).getLength() * relPosOnArrivalLink;
171 } else { // i.e. departure = arrival link
172 // subtract relative distance of arrival link that is not traveled
173 routeDistance -= network.getLinks().get(networkRoute.getEndLinkId()).getLength() * (1.0 - relPosOnArrivalLink);
174 }
175 return routeDistance;
176 }
However, from the debugging screenshot below, the route
does not contain the startLink
and endLink
. Only the intermediate links between start and end are contained in the route
. This implies that the endLink
is not considered for the calculation of travel time.
Here is an illustration of the relevant leg from the debugging screenshot
![]()
In Line 105 below, the calculation of travTime
is performed using the least cost path calculation of the routing algorithm and this requires arguments for startNode
and endNode
matsim-org: NetworkRoutingModule.calcRoute()
95 if (toLink != fromLink) {
96 // (a "true" route)
97 Node startNode = fromLink.getToNode(); // start at the end of the "current" link
98 Node endNode = toLink.getFromNode(); // the target is the start of the link
99
100 /* The NetworkInclAccessEgressModule actually looks up the vehicle in the scenario and passes it to the routeAlgo as well as to the resulting route.
101
105 Path path = this.routeAlgo.calcLeastCostPath(startNode, endNode, departureTime, person, null);
106 if (path == null)
107 throw new RuntimeException("No route found from node " + startNode.getId() + " to node " + endNode.getId() + " by mode " + this.mode + ".");
108 NetworkRoute route = this.populationFactory.getRouteFactories().createRoute(NetworkRoute.class, fromLink.getId(), toLink.getId());
109 route.setLinkIds(fromLink.getId(), NetworkUtils.getLinkIds(path.links), toLink.getId());
110 route.setTravelTime(path.travelTime);
111 route.setTravelCost(path.travelCost);
112 route.setDistance(RouteUtils.calcDistance(route, 1.0, 1.0, this.network));
113 newLeg.setRoute(route);
114 newLeg.setTravelTime(path.travelTime);
115 }
In line 98, the start of the
endLink
is used to initialize theendNode
. This excludes the link from travel time calculation.
Considering the need to account for theendLink
in the total distance of theleg
, I imagine the relevant node should be the end of theendLink
. This allows the algorithm to inlude the link during travel time calculation.
This is Line 98 currently:
98 Node endNode = toLink.getFromNode(); // the target is the start of the link
Here's my suggestion for a solution:
98 Node endNode = toLink.getToNode(); // the target is the end of the link
Before we continue with this: are your speed computations coming from events, or from something else? In general, only the events contain interpretable information. Plans, in contrast, are based on approximative models. This is the same difference as between genotype (= plan) and phenotype (= events) in genetics.
Hi @kainagel,
I just posted an update.
We might have posted within minutes of each other, so there's a chance you didn't see it.
@Ibraheem-A But Kais question remains - also after your update: Are you doing your analysis / observation based on the event
s or just on the plan
s (as they are written out e.g. in the carriers file)?
My speed computations are from observations obtained using event handlers. I understand that this should produce the same output as the event file. Is this correct?
Following @kainagel's question, I checked the output event file and searched for the leg of the single datapoint in my second post here. I found the travel time in the event to be adequate for the leg.
Vehicle enters traffic at 32543 and leaves traffic at 32557, which means the travel time is 14 seconds for 164.05 metres (average speed ~11.7m/s -- 42.2km/h). This is reasonably less than the link freespeed
and the maxVelocity
of the vehicle
<event time="32543.0" type="actend" person="Dr4|0|0" link="1141076970002f" x="4348004.0044760555" y="5941272.86786586" actType="service" />
<event time="32543.0" type="departure" person="Dr4|0|0" link="1141076970002f" legMode="car" computationalRoutingMode="car" />
<event time="32543.0" type="PersonEntersVehicle" person="Dr4|0|0" vehicle="Dr4|0|0_car" />
<event time="32543.0" type="vehicle enters traffic" person="Dr4|0|0" link="1141076970002f" vehicle="Dr4|0|0_car" networkMode="car" relativePosition="1.0" />
<event time="32544.0" type="left link" link="1141076970002f" vehicle="Dr4|0|0_car" />
<event time="32544.0" type="entered link" link="92528380001f" vehicle="Dr4|0|0_car" />
<event time="32546.0" type="left link" link="92528380001f" vehicle="Dr4|0|0_car" />
<event time="32546.0" type="entered link" link="8129844180000f" vehicle="Dr4|0|0_car" />
<event time="32548.0" type="left link" link="8129844180000f" vehicle="Dr4|0|0_car" />
<event time="32548.0" type="entered link" link="1379264710003f" vehicle="Dr4|0|0_car" />
<event time="32557.0" type="vehicle leaves traffic" person="Dr4|0|0" link="1379264710003f" vehicle="Dr4|0|0_car" networkMode="car" relativePosition="1.0" />
<event time="32557.0" type="PersonLeavesVehicle" person="Dr4|0|0" vehicle="Dr4|0|0_car" />
<event time="32557.0" type="arrival" person="Dr4|0|0" link="1379264710003f" legMode="car" />
<event time="32557.0" type="actstart" person="Dr4|0|0" link="1379264710003f" x="4348026.885355606" y="5941151.1690543825" actType="service" />
I've uploaded the class handling the events for my analysis here speedspike-TravelTimeEvaluator perhaps there's an issue with the way I set up the handlers.
After digging further, I identified a bug in the way the observations from the event handler are consumed on my side.
In my analysis class, where the observations of the event handler are consumed, the distance of the destination link at the end of one leg is counted again at the begining of the following leg. This coincidentally produces values that are similar to the strange values in the plan's computation, hence my confusion.
Once I resolve this, my observations should have exactly the same values as the events file.
Many thanks for comments, pointers and questions @kainagel @kt86. They were very helpful in solving this mystery. :)
One last question for clarification before closing this, is the behaviour described here #1102 (comment) intended or is the computation of the plan's route simply irrelevant in the grand scheme and has no bearing on anything?