Skip to content

Commit b75d7b4

Browse files
authored
Merge pull request opentripplanner#7318 from HSLdevcom/add-viapoint-to-speedtest
Add categories, complicated areas, and viapoints to Helsinki performance test
2 parents 588afab + dbac0e1 commit b75d7b4

10 files changed

Lines changed: 1815 additions & 1428 deletions

File tree

application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTestRequest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ RouteRequest toRouteRequest() {
6262

6363
builder.withFrom(input.fromPlace()).withTo(input.toPlace());
6464

65+
if (input.viaLocation() != null) {
66+
builder.withViaLocations(List.of(input.viaLocation()));
67+
}
68+
6569
// Filter the results inside the SpeedTest, not in the itineraries filter,
6670
// when ignoring street results. This will use the default which is 50.
6771
if (!config.ignoreStreetResults()) {

application/src/test/java/org/opentripplanner/transit/speed_test/model/testcase/TestCaseDefinition.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.opentripplanner.transit.speed_test.model.testcase;
22

33
import java.time.Duration;
4+
import javax.annotation.Nullable;
45
import org.opentripplanner.api.parameter.QualifiedModeSet;
56
import org.opentripplanner.model.GenericLocation;
7+
import org.opentripplanner.routing.api.request.via.VisitViaLocation;
68
import org.opentripplanner.utils.time.DurationUtils;
79
import org.opentripplanner.utils.time.TimeUtils;
810
import org.opentripplanner.utils.tostring.ValueObjectToStringBuilder;
@@ -15,8 +17,9 @@ public record TestCaseDefinition(
1517
Duration window,
1618
GenericLocation fromPlace,
1719
GenericLocation toPlace,
20+
@Nullable VisitViaLocation viaLocation,
1821
/**
19-
* A test cases can be grouped into a category used to group similar cases, like "Flex" or
22+
* A test case can be grouped into a category used to group similar cases, like "Flex" or
2023
* "Long Distance".
2124
*/
2225
String category,
@@ -25,11 +28,13 @@ public record TestCaseDefinition(
2528
@Override
2629
public String toString() {
2730
return String.format(
28-
"#%s %s - %s, %s - %s, %s-%s(%s)",
31+
"#%s %s - via:%s - %s, %s - via:%s - %s, %s-%s(%s)",
2932
id,
3033
fromPlace.label,
34+
viaLocation != null ? viaLocation.label() : null,
3135
toPlace.label,
3236
coordinateString(fromPlace),
37+
viaLocation != null ? coordinateString(viaLocation.coordinateLocation()) : null,
3338
coordinateString(toPlace),
3439
TimeUtils.timeToStrCompact(departureTime, TestCase.NOT_SET),
3540
TimeUtils.timeToStrCompact(arrivalTime, TestCase.NOT_SET),

application/src/test/java/org/opentripplanner/transit/speed_test/model/testcase/io/TestCaseDefinitionCsvFile.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
import java.io.File;
44
import java.io.IOException;
5+
import java.util.List;
6+
import javax.annotation.Nullable;
57
import org.opentripplanner.api.parameter.QualifiedModeSet;
68
import org.opentripplanner.core.model.id.FeedScopedId;
79
import org.opentripplanner.model.GenericLocation;
10+
import org.opentripplanner.routing.api.request.via.VisitViaLocation;
11+
import org.opentripplanner.street.geometry.WgsCoordinate;
812
import org.opentripplanner.transit.speed_test.model.testcase.TestCaseDefinition;
913

1014
public class TestCaseDefinitionCsvFile extends AbstractCsvFile<TestCaseDefinition> {
@@ -41,8 +45,23 @@ TestCaseDefinition parseRow() throws IOException {
4145
parseDouble("toLat"),
4246
parseDouble("toLon")
4347
),
48+
parseViaLocation(),
4449
parseString("category"),
4550
new QualifiedModeSet(parseCollection("modes").toArray(new String[0]))
4651
);
4752
}
53+
54+
@Nullable
55+
private VisitViaLocation parseViaLocation() {
56+
try {
57+
return new VisitViaLocation(
58+
parseString("viaLabel"),
59+
parseDuration("viaMinimumWaitTime"),
60+
List.of(),
61+
new WgsCoordinate(parseDouble("viaLat"), parseDouble("viaLon"))
62+
);
63+
} catch (Exception e) {
64+
return null;
65+
}
66+
}
4867
}

test/performance/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,60 @@ The results will be displayed in the console.
2222
The test is run after every merge to dev-2.x. Its GitHub Actions workflow is defined
2323
in [performance-test.yml](/.github/workflows/performance-test.yml).
2424

25+
### Running the test manually
26+
27+
Sometimes it is desirable to run the test configuration in the CI environment manually, for
28+
example, when making changes to the tests. To do this, perform these steps:
29+
1. Create a local branch in git that contains the desired performance test configuration.
30+
2. In [performance-test.yml](/.github/workflows/performance-test.yml) add your test branch name to
31+
the configuration and change all `profile`s to `core`:
32+
```diff
33+
name: Performance test
34+
35+
on:
36+
push:
37+
branches:
38+
- dev-2.x
39+
+ - test-branch-name
40+
41+
jobs:
42+
perf-test:
43+
if: github.repository_owner == 'opentripplanner' && !startsWith(github.event.head_commit.message ,'Bump serialization version id for') && !startsWith(github.event.head_commit.message ,'Upgrade debug client to version')
44+
runs-on: performance-test
45+
strategy:
46+
fail-fast: false
47+
matrix:
48+
include:
49+
...
50+
- location: baden-wuerttemberg # German state of Baden-Württemberg: https://en.wikipedia.org/wiki/Baden-W%C3%BCrttemberg
51+
iterations: 1
52+
jfr-delay: "50s"
53+
- profile: extended
54+
+ profile: core
55+
56+
- location: switzerland
57+
iterations: 1
58+
jfr-delay: "50s"
59+
- profile: extended
60+
+ profile: core
61+
62+
- location: washington-state
63+
iterations: 1
64+
jfr-delay: "20s"
65+
- profile: extended
66+
+ profile: core
67+
68+
- location: helsinki
69+
iterations: 1
70+
jfr-delay: "50s"
71+
- profile: extended
72+
+ profile: core
73+
...
74+
```
75+
3. Commit the changes to [performance-test.yml](/.github/workflows/performance-test.yml).
76+
4. Push the changes to a branch in the **upstream** [OpenTripPlanner](https://github.com/opentripplanner/OpenTripPlanner/) repository with the same name you added to [performance-test.yml](/.github/workflows/performance-test.yml).
77+
5. The tests will run after the push.
78+
2579
## Instrumentation
2680

2781
Each run on CI is instrumented with Java Flight Recorder. The results are then saved as an artifact

test/performance/helsinki/build-config.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"maxAreaNodes": 1000,
88
"maxTransferDuration": "26m",
99
"multiThreadElevationCalculations": true,
10-
"transitServiceStart": "2026-01-01",
11-
"transitServiceEnd": "2026-01-31",
10+
"transitServiceStart": "2026-02-01",
11+
"transitServiceEnd": "2026-02-28",
1212
"transitModelTimeZone": "Europe/Helsinki",
1313
"fares": "hsl",
1414
"transferRequests": [
@@ -40,13 +40,13 @@
4040
"transitFeeds": [
4141
{
4242
"type": "gtfs",
43-
"source": "https://otp-performance.leonard.io/data/helsinki/hsl-gtfs-2026-01-12.zip",
43+
"source": "https://otp-performance.leonard.io/data/helsinki/hsl-gtfs-2026-02-19.zip",
4444
"feedId": "HSL"
4545
}
4646
],
4747
"osm": [
4848
{
49-
"source": "https://otp-performance.leonard.io/data/helsinki/hsl-2026-01-12.osm.pbf"
49+
"source": "https://otp-performance.leonard.io/data/helsinki/hsl-2026-02-19.osm.pbf"
5050
}
5151
]
5252
}

test/performance/helsinki/generate_test_cases.py

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import csv
22

33
fieldnames = ["testCaseId", "description", "departure", "arrival", "fromLat",
4-
"fromLon", "toLat", "toLon", "origin", "destination", "modes", "category"]
4+
"fromLon", "toLat", "toLon", "origin", "destination", "modes", "category",
5+
"viaLabel", "viaMinimumWaitTime", "viaLat", "viaLon"]
56

67
locations = [
78
# Helsinki
89
{
9-
"coordinates": "60.169665, 24.934652",
10+
"coordinates": "60.169665,24.934652",
1011
"name": "Kamppi"
1112
},
1213
{
13-
"coordinates": "60.179022, 24.924151",
14+
"coordinates": "60.179022,24.924151",
1415
"name": "Töölöntori"
1516
},
1617
{
17-
"coordinates": "60.22070, 24.86094",
18+
"coordinates": "60.22070,24.86094",
1819
"name": "Pitäjänmäki"
1920
},
2021
{
21-
"coordinates": "60.20863, 25.07946",
22+
"coordinates": "60.20863,25.07946",
2223
"name": "Itäkeskus"
2324
},
2425
{
@@ -27,46 +28,77 @@
2728
},
2829
# Espoo
2930
{
30-
"coordinates": "60.18234, 24.82531",
31+
"coordinates": "60.18234,24.82531",
3132
"name": "Otaniemi"
3233
},
3334
{
34-
"coordinates": "60.205940, 24.656711",
35+
"coordinates": "60.205940,24.656711",
3536
"name": "Espoon Keskusta"
3637
},
3738
{
38-
"coordinates": "60.15509, 24.74546",
39+
"coordinates": "60.15509,24.74546",
3940
"name": "Matinkylä"
4041
},
4142
{
42-
"coordinates": "60.19586, 24.58912",
43+
"coordinates": "60.19586,24.58912",
4344
"name": "Kauklahti"
4445
},
4546
{
46-
"coordinates": "60.29030, 24.56324",
47+
"coordinates": "60.29030,24.56324",
4748
"name": "Nuuksio"
4849
},
4950
{
50-
"coordinates": "60.17892, 24.65813",
51+
"coordinates": "60.17892,24.65813",
5152
"name": "Latokaski"
5253
},
5354
# Vantaa
5455
{
55-
"coordinates": "60.29246, 25.03861",
56+
"coordinates": "60.29246,25.03861",
5657
"name": "Tikkurila"
5758
},
5859
# Airport
5960
{
60-
"coordinates": "60.317508, 24.969089",
61+
"coordinates": "60.317508,24.969089",
6162
"name": "Airport"
6263
},
6364
# Kirkkonummi
6465
{
65-
"coordinates": "60.12640, 24.43613",
66+
"coordinates": "60.12640,24.43613",
6667
"name": "Kirkkonummi"
6768
}
6869
]
6970

71+
complicated_area_locations = [
72+
# Helsinki
73+
{
74+
"coordinates": "60.17188,24.93951",
75+
"name": "Elielinaukio"
76+
},
77+
{
78+
"coordinates": "60.16758,24.95410",
79+
"name": "Kauppatori"
80+
},
81+
{
82+
"coordinates": "60.16968,24.93486",
83+
"name": "Narinkkatori"
84+
},
85+
# Espoo
86+
{
87+
"coordinates": "60.17685,24.80548",
88+
"name": "Tapionraitti"
89+
},
90+
# Kauniainen
91+
{
92+
"coordinates": "60.21073,24.72707",
93+
"name": "Thurmaninaukio"
94+
},
95+
# Kirkkonummi
96+
{
97+
"coordinates": "60.11974,24.43999",
98+
"name": "Asema-aukio"
99+
}
100+
]
101+
70102
arrival = "13:00"
71103
departure = "13:00"
72104

@@ -80,6 +112,8 @@ def parse_coords(input):
80112
}
81113

82114
counter = 0
115+
116+
# depart-after
83117
for start in locations:
84118
for end in locations:
85119
if end["coordinates"] is not start["coordinates"]:
@@ -88,7 +122,6 @@ def parse_coords(input):
88122
end_coords = parse_coords(end["coordinates"])
89123

90124
counter = counter + 1
91-
92125
rows.append({
93126
"testCaseId": counter,
94127
"description": f'{start["name"]} to {end["name"]} (transit)',
@@ -100,9 +133,10 @@ def parse_coords(input):
100133
"origin": start["name"],
101134
"destination": end["name"],
102135
"modes": "TRANSIT|WALK",
103-
"category": "transit"
136+
"category": "depart-after"
104137
})
105138

139+
# arrive-by
106140
for start in locations:
107141
for end in locations:
108142
if end["coordinates"] is not start["coordinates"]:
@@ -111,7 +145,6 @@ def parse_coords(input):
111145
end_coords = parse_coords(end["coordinates"])
112146

113147
counter = counter + 1
114-
115148
rows.append({
116149
"testCaseId": counter,
117150
"description": f'{start["name"]} to {end["name"]} (transit)',
@@ -123,9 +156,60 @@ def parse_coords(input):
123156
"origin": start["name"],
124157
"destination": end["name"],
125158
"modes": "TRANSIT|WALK",
126-
"category": "transit"
159+
"category": "arrive-by"
127160
})
128161

162+
# complicated-area
163+
for start in complicated_area_locations:
164+
for end in complicated_area_locations:
165+
if end["coordinates"] is not start["coordinates"]:
166+
167+
start_coords = parse_coords(start["coordinates"])
168+
end_coords = parse_coords(end["coordinates"])
169+
170+
counter = counter + 1
171+
rows.append({
172+
"testCaseId": counter,
173+
"description": f'{start["name"]} to {end["name"]} (transit)',
174+
"departure": departure,
175+
"fromLat": start_coords["lat"],
176+
"fromLon": start_coords["lon"],
177+
"toLat": end_coords["lat"],
178+
"toLon": end_coords["lon"],
179+
"origin": start["name"],
180+
"destination": end["name"],
181+
"modes": "TRANSIT|WALK",
182+
"category": "complicated-area"
183+
})
184+
185+
# viapoint
186+
via_start = complicated_area_locations[0]
187+
via_end = complicated_area_locations[1]
188+
via_start_coords = parse_coords(via_start["coordinates"])
189+
via_end_coords = parse_coords(via_end["coordinates"])
190+
via_locations = locations
191+
for via_location in via_locations:
192+
via_coords = parse_coords(via_location["coordinates"])
193+
194+
counter = counter + 1
195+
rows.append({
196+
"testCaseId": counter,
197+
"description": f'{via_start["name"]} to {via_end["name"]} (transit)',
198+
"departure": departure,
199+
"fromLat": via_start_coords["lat"],
200+
"fromLon": via_start_coords["lon"],
201+
"toLat": via_end_coords["lat"],
202+
"toLon": via_end_coords["lon"],
203+
"origin": via_start["name"],
204+
"destination": via_end["name"],
205+
"modes": "TRANSIT|WALK",
206+
"category": "viapoint",
207+
"viaLabel": via_location["name"],
208+
"viaMinimumWaitTime": "60s",
209+
"viaLat": via_coords["lat"],
210+
"viaLon": via_coords["lon"]
211+
})
212+
129213
with open('travelSearch.csv', 'w', encoding='UTF8', newline='') as f:
130214
writer = csv.DictWriter(f, fieldnames=fieldnames)
131215
writer.writeheader()

0 commit comments

Comments
 (0)