[00:00.000 --> 00:11.640] So, welcome everybody. My name is Hannes Jornilla. I've worked with OpenTrip Planner, which is [00:11.640 --> 00:18.440] an open source journey planner, quite similar to the MOTIS project for almost 10 years now, [00:18.440 --> 00:24.040] a bit on and off, so with other projects as well, and for all kinds of different [00:24.040 --> 00:31.520] organisations both in Finland and now at the moment in Norway. But before we talk about the [00:31.520 --> 00:37.480] project itself, I would like to say a couple of words about Entur. So, I don't think Entur is [00:37.480 --> 00:42.240] as famous company as some of the other ones that we have today, but it's actually, it used to be [00:42.240 --> 00:49.800] a part of the Norwegian state railway company, and it was carved out when competition was introduced [00:49.800 --> 00:57.200] in the Norwegian railway system, and nowadays it takes care of all ticketing, all public transit [00:57.200 --> 01:05.560] timetable information in the whole country of Norway. And we use almost exclusively open source [01:05.560 --> 01:12.240] software, at least in our team, which handles the incoming transit data, all the journey planning, [01:12.240 --> 01:19.520] all the APIs that we provide for all of the railway companies, all of the other hobbyists [01:19.520 --> 01:25.560] that want to have a journey planner, API, or like a screen at their home, any kind of API we can [01:25.560 --> 01:31.760] provide that. And here in the middle is open tree planner, which is quite the key component. [01:31.760 --> 01:39.760] So, first, I will talk a bit about the past. So, how did we come here? What was open tree [01:39.760 --> 01:47.200] planner in the origin? How has it evolved over the years? What were some pain points in the [01:47.200 --> 01:52.800] history? Then I will spend most of the time with open tree planner 2, which we released two years [01:52.800 --> 01:58.560] ago, and have since continued to develop. And finally, I will have a couple of minutes to [01:58.560 --> 02:06.040] discuss some topics that we will be implementing in the future. But before I start, I would like [02:06.040 --> 02:10.520] to see in the audience, how many of you have heard about the project before? Can I have some [02:10.520 --> 02:17.160] hands? So, about a half, I would say. How many of you have actually tested it yourself? So, [02:17.160 --> 02:22.600] almost as many, which is a good sign, because I think it's very important for an open source [02:22.600 --> 02:30.680] project that it's easy to get going with it. It's easy to take into use. And yeah, as I mentioned [02:30.680 --> 02:36.920] already in the beginning, open tree planner or OTP, as I will probably reference it, is quite [02:36.920 --> 02:44.080] similar project to the MOTIS project that we have had presenting. So, it's a passenger information [02:44.080 --> 02:52.080] system for transit data and other multimodal services, and it handles journey planning, [02:52.080 --> 02:59.240] but it also has APIs for just querying the data. So, here we can see how the number of [02:59.240 --> 03:07.440] commits to the repository has been over the years. So, it started in 2009 in Portland, Oregon, [03:07.440 --> 03:16.040] in the US, and they wanted to build a journey planner that was open source. So, they took in [03:16.040 --> 03:21.720] people that had been contributing to other libraries or projects that involved journey [03:21.720 --> 03:28.520] planning, transit data, other kinds of projects and took them into the room and said, okay, [03:28.520 --> 03:35.080] we'll give you money, just build us the software. And then, about a year later, it was put into [03:35.080 --> 03:41.600] production, and in 2013, the people involved started a company called Conveil, which took over [03:41.600 --> 03:50.200] the maintenance. But over the years, that company has actually gone more towards the [03:50.200 --> 03:57.800] direction of transit analysis, so doing software for the different cities, the different transit [03:57.800 --> 04:04.400] authorities, similarity what we actually have already seen today. But in 2013, a really [04:04.400 --> 04:10.000] important step was taken. There was a big project with the Dutch government for improving [04:10.000 --> 04:15.600] multimodal transit data and real-time data. But at the same time, there was a second project [04:15.600 --> 04:24.880] that was included in the bigger Dutch project called R4, which was implementing the Raptor [04:24.880 --> 04:31.520] algorithm in an open source. And then, it was later rewritten in R5, which is a software [04:31.520 --> 04:40.320] by Conveil. 2016, there was new deployments in Washington, DC, the New York State, Oslo, [04:40.320 --> 04:49.360] Helsinki, so a bit all over the place, and there was some trials with nationwide scaling. [04:49.360 --> 04:58.640] But then, the project kind of stagnated until 2018, 2019, when Entoor and Router two Norwegian [04:58.640 --> 05:05.360] companies took over the responsibility and ported over the Raptor algorithm from the [05:05.360 --> 05:13.000] R5 project into OpenTrip Planner. And then, in 2020, we released the OpenTrip Planner [05:13.000 --> 05:20.040] 2. And here you can see, if I overlay the commits for the R5 project, you can see that, [05:20.040 --> 05:26.720] well, it was the project that took the focus in the meantime. So, what were the main pain [05:26.720 --> 05:33.800] points with OpenTrip Planner 1? The core issue is the journey planning algorithm that was [05:33.800 --> 05:39.040] selected. So, there was a time-dependent A-star search with trip banning that used over the [05:39.040 --> 05:44.840] whole network. So, both street network, transit network, the multimodal stuff, everything was [05:44.840 --> 05:53.360] in the same algorithm. And how it worked was that you run a search, then you get results, [05:53.360 --> 05:58.400] you ban all the trips that you were using, and then you rerun. So, it didn't scale that [05:58.400 --> 06:05.000] well when you wanted to have more results or a longer or larger graph. And also, it [06:05.000 --> 06:11.760] was more focused towards research capabilities. But these were then later on taken over by [06:11.760 --> 06:18.240] R5. And we removed quite a lot of this from OpenTrip Planner 2, focusing on the journey [06:18.240 --> 06:24.040] planning part. Also, there was a lack of kind of vision of where it should go, how it should [06:24.040 --> 06:31.560] be structured, everything. And also, there was development happening in many different [06:31.560 --> 06:37.720] repositories, and it was not really well-coordinated. So, for example, HSL, where the Digitransit [06:37.720 --> 06:46.120] project is, or who owns the Digitransit project, they have their own fork of the project that [06:46.120 --> 06:51.440] has quite a lot of added development. But that has now been mostly ported back to OpenTrip [06:51.440 --> 06:59.880] Planner 2. So, let's take a quick look at how it works. I think this is the main difference [06:59.880 --> 07:06.920] between OTP-1 and OTP-2. In OTP-1, as I said, all of the routing was done inside one single [07:06.920 --> 07:16.560] search. In OTP-2, we first get a request from the API. Then we run a street search. It's [07:16.560 --> 07:23.000] basically an A-star search, but just with a single mode, or with different modes if you [07:23.000 --> 07:30.080] want to have rental bicycle, rental scooters, parking your car, or anything like that. Then [07:30.080 --> 07:37.760] we enrich this with flexible transit results for the last and first mile. Then we do a [07:37.760 --> 07:44.240] transit search using the Raptor algorithm. And finally, we have two post-processing steps [07:44.240 --> 07:51.760] that I will talk a bit about later on. And then we send the result out in the API. So, [07:51.760 --> 07:58.120] the street search is actually pretty much the same as it was in OpenTrip Planner 1. There [07:58.120 --> 08:03.560] is some improvements. There is, for example, free-floating vehicles, new types of vehicles, [08:03.560 --> 08:11.720] so scooters, real-time parking information so that if you do a park-and-ride search, [08:11.720 --> 08:17.040] it will actually only be suggested to park at a place where we know that there probably [08:17.040 --> 08:24.320] will be space. And also, there is improved focus on this kind of quality of the routing, [08:24.320 --> 08:30.320] so there is a walk safety score so that we prefer, for example, walking through nice [08:30.320 --> 08:39.960] gardens or other paths that are not next to a big motorway. Yeah, so I mentioned flexible [08:39.960 --> 08:45.560] routes. So, most of you would assume that this is, or think about this when you think [08:45.560 --> 08:51.280] about transit timetables, so that you have fixed set of stops, fixed set of times. But [08:51.280 --> 08:56.400] there is many other ways that transit can be structured. So, you can have, for example, [08:56.400 --> 08:59.840] hail-and-ride sections where you actually don't have any stops, but you can just flag [08:59.840 --> 09:07.720] the bus anywhere you want. Or you can have areas, just one, two, or as many as you like. [09:07.720 --> 09:15.240] And the bus will deviate from its pre-assigned route and just drop you home or pick you [09:15.240 --> 09:26.120] up from the door. Or it can be a group of stops, some kind of feeder services that take you [09:26.120 --> 09:33.840] to the nearest railway station if there is no regular transit in the village. Or it can [09:33.840 --> 09:41.680] be as complex services as we like with any kind of combination. So, after we have added [09:41.680 --> 09:48.400] the flex results, we do a Raptor search where we insert all the street routing results, [09:48.400 --> 09:56.640] all the flexible results, and then we operate only on trips with fixed schedules and fixed [09:56.640 --> 10:03.680] stops. So, there is actually multiple levels of Raptor. So, Raptor is a algorithm that was [10:03.680 --> 10:12.000] introduced in 2012 by a researcher from Microsoft Research. And the basic Raptor, it has two [10:12.000 --> 10:18.480] criterias. So, it has arrival time and number of transit, and it departs at a fixed time. [10:18.480 --> 10:26.360] Basically, what you do is that you find all of the stops that you can walk to or make [10:26.360 --> 10:33.440] the street routing to, then you board all the vehicles from those stops, then you alight [10:33.440 --> 10:39.880] at every possible stop and find where you have arrived. Then you find all of the transfers [10:39.880 --> 10:46.440] from those stops to all other stops, and then you continue this in new rounds. So, this [10:46.440 --> 10:52.200] finds your results with the two criterias, the one with the shortest arrival time and [10:52.200 --> 11:00.240] the one with the least transfers. Then you can run this Range Raptor, which is basically [11:00.240 --> 11:05.520] just running the Raptor algorithm, but you start at the minute and then you run it backwards [11:05.520 --> 11:12.120] and adding new results to the beginning as you go. And then you get this tree criteria [11:12.120 --> 11:19.400] result that has the departure time, arrival time, and number of transfers. And that creates [11:19.400 --> 11:23.880] this kind of set where you have the departure time, arrival time, and number of transfers [11:23.880 --> 11:30.760] are all optimal. Then you can insert one or more criterias, like we're talking about [11:30.760 --> 11:38.000] that you want to optimize for CO2 usage or wheelchair accessibility or comfort that you [11:38.000 --> 11:46.560] only want to use transit that is not too crowded, any kind of numerical value you can [11:46.560 --> 11:52.920] add as a criteria, but that unfortunately has the downside that it quite heavily affects [11:52.920 --> 12:00.160] the performance. Yeah, so this is basically how we do. This is the result of the one round [12:00.160 --> 12:07.360] of Raptor search. This is of the two, three. You only add a few other leaves and then the [12:07.360 --> 12:12.080] last you just basically prune the results so that there is some where it's optimal to [12:12.080 --> 12:21.760] actually not use a trip with just one transfer, but you need to transfer many, many times. [12:21.760 --> 12:28.680] Then we do a process called transfer optimization. And this is especially in the railways where [12:28.680 --> 12:35.640] you can transfer between two trips at multiple stations. And it's actually the end result [12:35.640 --> 12:42.840] will be the same, independently of where you transfer. You will get home at the same time, [12:42.840 --> 12:49.600] but it might be nice to transfer somewhere where you have a roof over you, or maybe [12:49.600 --> 12:53.600] you have, if you have like one hour of time, you want to spend somewhere where you have [12:53.600 --> 13:01.840] access to a cafe, or then you want to make sure that you have a high probability of getting [13:01.840 --> 13:08.360] your transfer. So the one that is has the longest waiting time. And a specific type [13:08.360 --> 13:12.680] is this kind of back travel that you want to avoid that if you go from the blue dot [13:12.680 --> 13:17.120] to the red dot, you don't want to ride all over the last stop and then all the way back [13:17.120 --> 13:23.640] because that is most probably quite expensive. Then we do itinerary filtering and decorating. [13:23.640 --> 13:28.640] So the aim from the Raptor is to get as much results as possible. And then here we can [13:28.640 --> 13:35.320] make more intricate comparison between different results. And we can prune results that might [13:35.320 --> 13:41.760] be optimal, but are really bad compared to other ones. So for example, you might want [13:41.760 --> 13:46.200] to have, or you might have a result where you have just one, like no transfers, but [13:46.200 --> 13:51.880] you are expected to walk 45 minutes. And that's not really you probably want to do if you [13:51.880 --> 14:01.680] have a possibility to do it in 50 minutes less. Then a big thing in OpenTrip Planner [14:01.680 --> 14:09.080] 2 was the inclusion of a separate data model. So prior in OTP 1, the data model was based [14:09.080 --> 14:17.040] on the GTFS vocabulary and all the data was imported as the GTFS objects. But in OTP 2 [14:17.040 --> 14:23.520] we have an internal data model that is built so that we can import transit data from both [14:23.520 --> 14:33.520] netx and GTFS. So it's independent of data source and we can easily add new data sources. [14:33.520 --> 14:40.400] So there was for example a Swiss data set that somebody was looking at in importing [14:40.400 --> 14:48.400] into OpenTrip Planner. Then something that became really popular is the sandbox extensions. [14:48.400 --> 14:54.000] So we introduced a mechanism for plugging in an optional plugin into OpenTrip Planner [14:54.000 --> 15:01.560] 2 and this has been really successful with currently 22 different extensions existing. [15:01.560 --> 15:08.720] So you can provide new APIs, new data formats, new functionality that is maybe not ready [15:08.720 --> 15:14.200] to take into the core OpenTrip Planner but there is something that is in the process [15:14.200 --> 15:20.200] of development. Or you might want to have some functionality that is custom for your [15:20.200 --> 15:25.440] deployment but you want to make sure that it keeps up to date and that it's maintained [15:25.440 --> 15:35.040] and that if you do some changes in the data model or any code code that we have we will [15:35.040 --> 15:39.240] keep those updated. [15:39.240 --> 15:46.520] So one extension is that we now have two GraphQL APIs, one that is based on GTFS vocabulary [15:46.520 --> 15:52.200] and one that is based on Transmodel Vocabulary. And you can use import data for example in [15:52.200 --> 16:00.720] Skåne in the south of Sweden. They import Swedish timetables in netx and Danish timetables [16:00.720 --> 16:07.600] that they use for trips to Copenhagen in GTFS. And then you can use this unified API where [16:07.600 --> 16:13.560] you provide the data in standard format so that if you want to have the results in GTFS [16:13.560 --> 16:20.480] vocabulary you can get that but you can also get in Transmodel Vocabulary if you want it. [16:20.480 --> 16:24.520] And also GraphQL is really useful for this kind of journey planning purposes because [16:24.520 --> 16:29.440] usually you want to fetch little information about very many objects. And if you have this [16:29.440 --> 16:39.880] traditional very rest pure way you end up having like hundreds of queries that you need [16:39.880 --> 16:45.560] to do but with GraphQL you can fetch exactly the things that you need and only those and [16:45.560 --> 16:53.640] that also saves quite a lot of space for mobile apps where you can limit the number of downloaded [16:53.640 --> 17:01.920] bytes. Then we have vector tiles so you can query all the geometric information that we [17:01.920 --> 17:08.800] have just spatial information so all the stop stations, rental stations, even individual [17:08.800 --> 17:15.240] rental vehicles, car and bike parking and so on. And you can add real time information [17:15.240 --> 17:20.800] for those so that you can easily show a map where you have like the live availability [17:20.800 --> 17:29.960] of all the rental systems. And then one feature that actually we bought back from OTP2 was [17:29.960 --> 17:35.800] that that was removed as a sandbox extension and that is the travel time analysis. And [17:35.800 --> 17:42.640] this is a feature that sits somewhere between pure journey planning and pure research applications [17:42.640 --> 17:48.400] because this is really useful for some applications where you for example you are looking to buy [17:48.400 --> 17:54.160] a house and you can easily see okay like the on the web page of the seller they can show [17:54.160 --> 18:00.160] like this map that okay this is the area where you actually can get into with public transit [18:00.160 --> 18:07.520] in 15 minutes or buy car in 15 minutes or buy rental bikes in 15 minutes. So all of [18:07.520 --> 18:13.440] this is multimodal and you can export both geogasin so the borders of the areas or you [18:13.440 --> 18:19.120] can get a geotiff with actual second values of how many seconds does it does it take to [18:19.120 --> 18:29.920] get to this pixel on the map. One other big improvement that we did with OpenTriplanner2 [18:29.920 --> 18:35.160] is that we simplified the operations. OpenTriplanner1 expected that you always have a local file [18:35.160 --> 18:40.600] system and that you always have all the files on the local file system. But we abstracted [18:40.600 --> 18:48.160] this into a data source that is can be input or can be output or can be both. And currently [18:48.160 --> 18:52.840] we have local file system so you can still have everything in the local file system [18:52.840 --> 19:00.500] if you wish. You can fetch files over HTTPS and you can load and save data to all cloud [19:00.500 --> 19:04.480] storage services or at least all the major ones and it's really easy to create your [19:04.480 --> 19:14.080] own if you want. Yeah also there is improved monitoring support so you can get all the [19:14.080 --> 19:23.480] timing data of the internal algorithms really easily. We improved quite a lot of the documentation [19:23.480 --> 19:30.200] so you can find the link over there and actually with that new configuration structure this [19:30.200 --> 19:37.560] is all that you need in order to fetch all the data and build the graph for the entirety [19:37.560 --> 19:45.240] of the Belgian country. So you have four different operators. You just say that these are the [19:45.240 --> 19:50.360] paths to these. You can also say if you would have like for example the German netx feed [19:50.360 --> 19:56.680] you could have there as well and multiple open street map files. And with different [19:56.680 --> 20:01.960] tag mapping so different countries have different rules and regulations of whether you are allowed [20:01.960 --> 20:08.160] for example to walk on a bike path or if you are allowed to drive on the street if there [20:08.160 --> 20:13.920] is a bike path next to it and so on and that's why we have this customizable tag mapping [20:13.920 --> 20:21.040] so that each country or even city can have their own rules about how these things should [20:21.040 --> 20:29.320] be mapped. Yeah then a bit about the future what we are planning to do next. We of course [20:29.320 --> 20:35.600] continue all the time with feature development so we have built now during the winter via [20:35.600 --> 20:42.880] search that was not part of the initial OTP to release so that you can say that oh I want [20:42.880 --> 20:47.600] to go from here. I want to go to my hotel but actually I want to visit this bar in the [20:47.600 --> 20:53.240] between so you can get all the connections that are from here to the bar then you say [20:53.240 --> 20:57.880] that okay I want to spend about two hours in the bar and then you will get the results [20:57.880 --> 21:05.680] about two hours later from the bar to your hotel. The second one is GBFS geofencing areas [21:05.680 --> 21:10.680] so that you can limit where you can actually use your scooter if there is some places where [21:10.680 --> 21:15.720] you don't if you can park it you will be instructed to actually park it just before [21:15.720 --> 21:21.640] the zone starts or if you have speed limits it might be beneficial to drive around those [21:21.640 --> 21:29.440] speed limits. Then performance is something that we think is very important we have been [21:29.440 --> 21:36.840] focusing more and more of it and we started actually measuring it so we run a set of queries [21:36.840 --> 21:43.400] after each commit and we store them in a Postgres database and then we have a nice dashboard [21:43.400 --> 21:48.680] that's where you can go to and see how we have been doing over time and we have multiple [21:48.680 --> 21:55.200] data sets. It's so that if somebody is using this in production we can add their data set [21:55.200 --> 22:00.520] so that they can see how their data set is performing because different data sets have [22:00.520 --> 22:08.160] quite different performance characteristics because you might have a very large network [22:08.160 --> 22:13.680] or you might have a network with very strange timing conditions or other things that might [22:13.680 --> 22:21.760] affect it. We are also working on new internal data model for the timetable data that is [22:21.760 --> 22:27.880] better suited for Raptor that uses a virtual trip for heuristic calculations so that you [22:27.880 --> 22:34.160] don't actually need to do any timetable lookups and it's better memory or it's more memory [22:34.160 --> 22:39.040] efficient. So for example we noticed that most timetables actually only operate on full [22:39.040 --> 22:45.160] minutes and are less than four hours and a quarter so you can store them in just one [22:45.160 --> 22:53.160] daytime and an array of bytes. Then one thing that is actually touching there was a question [22:53.160 --> 23:02.120] about the international deployment so we run currently in Norway we run a Nordic graph [23:02.120 --> 23:08.240] that contains data for all the Nordic countries but we are working on this segmented or tiered [23:08.240 --> 23:17.200] model where we actually separate the transit networks into local and long distance and [23:17.200 --> 23:22.440] then we split those into smaller and we only take in the routing data that you need for [23:22.440 --> 23:29.960] your search. Then there is this competition neutrality so in Norway we have commercial [23:29.960 --> 23:37.360] bus operators and we have their data and unfortunately they do some awful tricks so for example they [23:37.360 --> 23:41.600] might schedule a trip that starts one minute later than the competitors and arrives one [23:41.600 --> 23:48.920] minute earlier and that way you actually drop the other operator completely from the results. [23:48.920 --> 23:57.120] So what we are planning is to add a Raptor criteria where we have a bit set of the commercial [23:57.120 --> 24:03.200] operators used and that makes it so that we will always suggest all the available options [24:03.200 --> 24:10.080] even though they are not optimal as long as they use a different carrier. And we are also [24:10.080 --> 24:15.360] planning for a unified GraphQL API where we would have one data model, one structure [24:15.360 --> 24:24.920] but two dialects, one for GTFS and one for Trans model in order to lower the overhead. [24:24.920 --> 24:38.120] So that was it, thank you very much. I think we might have time for one, two questions [24:38.120 --> 24:41.720] so if there is anybody in the audience. Yeah. [24:41.720 --> 24:50.920] Thank you for the presentation, that's very impressive regarding pedestrian routing. Yeah. [24:50.920 --> 24:56.880] So we take the data from OpenStreetMap and some areas have it better mop, some have it [24:56.880 --> 25:04.360] worse and we also use if you have in your GTFS we use this Pathways extension so you [25:04.360 --> 25:11.960] can model the inside of the train railway station and then we just link not the innards [25:11.960 --> 25:19.720] of the railway station but the entrances and then the inner model comes from the Pathways. [25:19.720 --> 25:24.720] There is also something similar available in netx but that we don't import at the moment. [25:24.720 --> 25:25.720] Yeah. [25:25.720 --> 25:28.720] Do you understand correctly that you have demand responsive? [25:28.720 --> 25:29.720] Yes. [25:29.720 --> 25:37.680] Yes. So that was the part about the flex search that is the second part before the timetable. [25:37.680 --> 25:40.720] So at the moment we only use it for first and last mile. [25:40.720 --> 25:45.200] But you only interface with external APIs to do their calculations? [25:45.200 --> 25:52.200] No, we don't do any availability so we just say that it might be possible to take this [25:52.200 --> 25:57.360] but you need to plan but that is something that you can implement in a filter so that [25:57.360 --> 26:02.960] the filter actually does the query of okay is this possible and then you can enhance [26:02.960 --> 26:05.200] the result with that data. [26:05.200 --> 26:06.200] Yeah. [26:06.200 --> 26:09.200] Very short question because there is no time. [26:09.200 --> 26:10.200] Yeah. [26:10.200 --> 26:19.200] So let's tell you international point of view with a different aspect optimization. [26:19.200 --> 26:20.200] Yeah. [26:20.200 --> 26:29.200] And so speed of transport with high speed train between Brussels and Berlin you pay a lot. [26:29.200 --> 26:30.200] Yeah. [26:30.200 --> 26:37.200] So when you go with the train and with the pedestrian you have the cheaper solution. [26:37.200 --> 26:38.200] Yeah. [26:38.200 --> 26:41.200] The bicycle is the optimal solution for me. [26:41.200 --> 26:42.200] Yeah. [26:42.200 --> 26:48.200] But I can just answer quickly that price is something that you can use as a Pareto criteria [26:48.200 --> 26:55.560] but the big problem is that there is so much dynamic fears that exist today that it's impossible [26:55.560 --> 27:19.560] to use it because there would be the.