matsim-org / matsim-code-examples

A repository containing code examples around MATSim
GNU General Public License v3.0
81 stars 178 forks source link

Trip-based Network Routing Disutility #1121

Open manserpa opened 4 months ago

manserpa commented 4 months ago

Hi all,

Consider following use-case: highway infrastructure (sequence of links) with multiple toll gates, i.e.: link 1 (with toll gate) -> link 2 -> link 3 -> link 4 (with toll gate) -> link 5

The toll for using this infrastructure must only be paid once per trip (trip-based tolling).

An agents now travels from link 1 to link 5. In the mobsim, it is quite straight forward to track the event sequence and only process a personMoneyEvent whenever the agent passes a toll gate for the first time during a trip.

What I'm more concerned about is the routing part. The TravelDisutility interface gives the option to add the toll on a link level, but not on a trip level (as far as I'm aware). As a result, the above route gets charged twice suggesting the route to be less attractive than in reality.

I was scanning through the code to see if this has been done before, but couldn't find anything and I'm not sure if it is even possible given the structure of the routing algorithm.

Any hints on how we could implement this are very appreciated - many thanks!

Janekdererste commented 4 months ago

I am not sure, how to approach this problem either, but since no one has answered, I will suggest something anyway:

From browsing the router code a little, it seems like the router instance maintains one instance of TravelDisutility and calls double travelCost = this.td.getLinkTravelDisutility(link, currTime, person, vehicle); for each link in the choice set for the route. It seems like currTime is the same value for all links.

A first idea would be to implement your own TravelDisutility. In this structure, you could charge disutility for the first tollgate, remember, that a toll was charged for queries of currTime and vehicle and delegate all other queries to the default TravelDisutility implementation.

JWJoubert commented 4 months ago

@manserpa, you might try the roadpricing contrib. In there, you could implement your own version of the TollFactor interface. If you have a Map that keeps track of the persons that already incurred toll, you could ignore persons when they have a second toll instance. This would be similar to what we did in this paper where the toll was aggregated per person until some daily cap was reached. At the end of the day, we reset the toll tally.

In your case, you'd create a personMoneyEvent once the trip ends, and then resets it (remove that individual from the map). Could that be something that can work for you?

manserpa commented 4 months ago

Thanks @Janekdererste and @JWJoubert , really helpful!

In your case, you'd create a personMoneyEvent once the trip ends, and then resets it (remove that individual from the map).

That's precisely what we are doing at the moment. In fact, we are facing a quite complex system of various new infrastructure projects on a national scale, each of which with their own toll schemes and daily caps. We successfully implemented that into the event processing using a custom RoadPricingScheme implementation with toll factors.

However, I don't think the toll factors make their way into the travel disutility of the network router, but could be wrong? Did you consider the caps during the routing stage?

you could charge disutility for the first tollgate, remember, that a toll was charged for queries of currTime and vehicle and delegate all other queries to the default TravelDisutility implementation.

Good idea - that sounds promising, we'll give it a go!

Really appreciate your support

EDIT: @JWJoubert I just went through your cited paper and found "2.4 A diversity generating router" - that sounds very sensible to me and a good path forward too.