Skip to content

Commit 12e0955

Browse files
committed
core: stdcm: tests: add tests that check spacing requirements
1 parent 093f288 commit 12e0955

File tree

3 files changed

+81
-11
lines changed

3 files changed

+81
-11
lines changed

core/src/main/java/fr/sncf/osrd/api/stdcm/STDCMEndpoint.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private static List<STDCMStep> parseSteps(FullInfra infra, List<STDCMRequest.STD
132132
}
133133

134134
/** Generate a train schedule matching the envelope and rolling stock, with one stop at the end */
135-
private static StandaloneTrainSchedule makeTrainSchedule(
135+
public static StandaloneTrainSchedule makeTrainSchedule(
136136
double endPos,
137137
RollingStock rollingStock,
138138
RollingStock.Comfort comfort,

core/src/test/java/fr/sncf/osrd/stdcm/FullSTDCMTests.java

+65-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
package fr.sncf.osrd.stdcm;
22

33
import static fr.sncf.osrd.Helpers.getExampleRollingStock;
4+
import static fr.sncf.osrd.api.stdcm.STDCMEndpoint.makeTrainSchedule;
5+
import static fr.sncf.osrd.train.TestTrains.REALISTIC_FAST_TRAIN;
46
import static org.junit.jupiter.api.Assertions.assertNotNull;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
58

9+
import com.google.common.collect.HashMultimap;
610
import fr.sncf.osrd.Helpers;
11+
import fr.sncf.osrd.api.FullInfra;
712
import fr.sncf.osrd.railjson.parser.RJSRollingStockParser;
13+
import fr.sncf.osrd.standalone_sim.ScheduleMetadataExtractor;
14+
import fr.sncf.osrd.standalone_sim.result.ResultTrain;
15+
import fr.sncf.osrd.train.RollingStock;
816
import fr.sncf.osrd.utils.units.Distance;
917
import org.junit.jupiter.api.Test;
1018
import java.io.IOException;
1119
import java.net.URISyntaxException;
20+
import java.util.List;
1221
import java.util.Set;
1322

1423
public class FullSTDCMTests {
@@ -42,9 +51,12 @@ public void testTinyInfraSmallOpening() throws IOException, URISyntaxException {
4251
"rt.buffer_stop_b->tde.foo_b-switch_foo", Distance.fromMeters(100)));
4352
var end = Set.of(Helpers.convertRouteLocation(infra,
4453
"rt.tde.foo_b-switch_foo->buffer_stop_c", Distance.fromMeters(10125)));
45-
var occupancies = STDCMHelpers.makeOccupancyFromPath(infra, start, end, 0);
54+
var requirements = STDCMHelpers.makeRequirementsFromPath(infra, start, end, 0);
55+
var occupancies = STDCMHelpers.makeOccupancyFromRequirements(infra, requirements);
4656
double minDelay = STDCMHelpers.getMaxOccupancyLength(occupancies); // Eventually we may need to add a % margin
47-
occupancies.putAll(STDCMHelpers.makeOccupancyFromPath(infra, start, end, minDelay * 2));
57+
occupancies.putAll(STDCMHelpers.makeOccupancyFromRequirements(infra,
58+
STDCMHelpers.makeRequirementsFromPath(infra, start, end, minDelay * 2)
59+
));
4860
var res = new STDCMPathfindingBuilder()
4961
.setInfra(infra)
5062
.setStartTime(minDelay)
@@ -53,6 +65,7 @@ public void testTinyInfraSmallOpening() throws IOException, URISyntaxException {
5365
.setUnavailableTimes(occupancies)
5466
.run();
5567
assertNotNull(res);
68+
checkNoConflict(infra, requirements, res);
5669
}
5770

5871
/** We try to fit a train in a short opening between two trains, this time on small_infra */
@@ -63,15 +76,62 @@ public void testSmallInfraSmallOpening() throws IOException, URISyntaxException
6376
"rt.buffer_stop.3->DB0", Distance.fromMeters(1590)));
6477
var end = Set.of(Helpers.convertRouteLocation(infra,
6578
"rt.DH2->buffer_stop.7", Distance.fromMeters(5000)));
66-
var occupancies = STDCMHelpers.makeOccupancyFromPath(infra, start, end, 0);
67-
occupancies.putAll(STDCMHelpers.makeOccupancyFromPath(infra, start, end, 600));
79+
var requirements = STDCMHelpers.makeRequirementsFromPath(infra, start, end, 0);
80+
requirements.addAll(STDCMHelpers.makeRequirementsFromPath(infra, start, end, 600));
6881
var res = new STDCMPathfindingBuilder()
6982
.setInfra(infra)
7083
.setStartTime(300)
7184
.setStartLocations(start)
7285
.setEndLocations(end)
73-
.setUnavailableTimes(occupancies)
86+
.setUnavailableTimes(STDCMHelpers.makeOccupancyFromRequirements(infra, requirements))
7487
.run();
7588
assertNotNull(res);
89+
checkNoConflict(infra, requirements, res);
90+
}
91+
92+
/** We make an opening that is just too small to fit a train,
93+
* we check that it isn't taken and doesn't cause conflicts */
94+
@Test
95+
public void testSmallInfraImpossibleOpening() throws IOException, URISyntaxException {
96+
var infra = Helpers.fullInfraFromRJS(Helpers.getExampleInfra("small_infra/infra.json"));
97+
var start = Set.of(Helpers.convertRouteLocation(infra,
98+
"rt.buffer_stop.3->DB0", Distance.fromMeters(1590)));
99+
var end = Set.of(Helpers.convertRouteLocation(infra,
100+
"rt.DH2->buffer_stop.7", Distance.fromMeters(5000)));
101+
var requirements = STDCMHelpers.makeRequirementsFromPath(infra, start, end, 0);
102+
var occupancies = STDCMHelpers.makeOccupancyFromRequirements(infra, requirements);
103+
double minDelay = STDCMHelpers.getMaxOccupancyLength(occupancies);
104+
occupancies.putAll(STDCMHelpers.makeOccupancyFromRequirements(infra,
105+
STDCMHelpers.makeRequirementsFromPath(infra, start, end, minDelay * 0.95)
106+
));
107+
var res = new STDCMPathfindingBuilder()
108+
.setInfra(infra)
109+
.setStartLocations(start)
110+
.setEndLocations(end)
111+
.setUnavailableTimes(STDCMHelpers.makeOccupancyFromRequirements(infra, requirements))
112+
.run();
113+
assertNotNull(res);
114+
checkNoConflict(infra, requirements, res);
115+
}
116+
117+
/** Check that the result we find doesn't cause a conflict */
118+
private void checkNoConflict(FullInfra infra, List<ResultTrain.SpacingRequirement> requirements, STDCMResult res) {
119+
var requirementMap = HashMultimap.<String, ResultTrain.SpacingRequirement>create();
120+
for (var requirement : requirements) {
121+
requirementMap.put(requirement.zone, requirement);
122+
}
123+
var newRequirements = ScheduleMetadataExtractor.run(
124+
res.envelope(),
125+
res.trainPath(),
126+
makeTrainSchedule(res.envelope().getEndPos(), REALISTIC_FAST_TRAIN,
127+
RollingStock.Comfort.STANDARD, res.stopResults()),
128+
infra
129+
).spacingRequirements;
130+
for (var requirement : newRequirements) {
131+
for (var existingRequirement : requirementMap.get(requirement.zone)) {
132+
assertTrue(requirement.beginTime > existingRequirement.endTime
133+
|| requirement.endTime < existingRequirement.beginTime);
134+
}
135+
}
76136
}
77137
}

core/src/test/java/fr/sncf/osrd/stdcm/STDCMHelpers.java

+15-5
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import java.util.Set;
2727

2828
public class STDCMHelpers {
29-
/** Make the occupancy multimap of a train going from point A to B starting at departureTime */
30-
public static Multimap<Integer, OccupancySegment> makeOccupancyFromPath(
29+
/**
30+
* Make the occupancy multimap of a train going from point A to B starting at departureTime
31+
*/
32+
public static List<ResultTrain.SpacingRequirement> makeRequirementsFromPath(
3133
FullInfra infra,
3234
Set<Pathfinding.EdgeLocation<Integer>> startLocations,
3335
Set<Pathfinding.EdgeLocation<Integer>> endLocations,
@@ -53,18 +55,26 @@ public static Multimap<Integer, OccupancySegment> makeOccupancyFromPath(
5355
new DriverBehaviour(0, 0)
5456
);
5557
var rawOccupancies = result.baseSimulations.get(0).spacingRequirements;
56-
var occupancies = new ArrayList<ResultTrain.SpacingRequirement>();
58+
var requirements = new ArrayList<ResultTrain.SpacingRequirement>();
5759
for (var entry : rawOccupancies) {
58-
occupancies.add(new ResultTrain.SpacingRequirement(
60+
requirements.add(new ResultTrain.SpacingRequirement(
5961
entry.zone,
6062
departureTime + entry.beginTime,
6163
departureTime + entry.endTime
6264
));
6365
}
66+
return requirements;
67+
}
68+
69+
/** Make the route occupancies from a spacing requirement list */
70+
public static Multimap<Integer, OccupancySegment> makeOccupancyFromRequirements(
71+
FullInfra infra,
72+
List<ResultTrain.SpacingRequirement> requirements
73+
) {
6474
return UnavailableSpaceBuilder.computeUnavailableSpace(
6575
infra.rawInfra(),
6676
infra.blockInfra(),
67-
occupancies,
77+
requirements,
6878
REALISTIC_FAST_TRAIN,
6979
0,
7080
0

0 commit comments

Comments
 (0)