Skip to content

Commit 1a87889

Browse files
committed
core: remove neutral section hacks to improve reliability
The current implementation of neutral ranges has at least two troublesome hacks: - when leaving a neutral section, the train takes time to start drawing power again. due to the design of the current implementation, this time is converted into an approximate distance - power is cut ahead of time using an announce zone, instead of having the driver react to the signal. this zone is there regardless of routes These hacks bring about several bugs: - the length of neutral section is extended by an approximation of the distance required to start drawing power again. This approximation is always too high if the train is slowing down. If the train is slowing down to a stop, it can get stuck in this approximated extension. This issue will vanish once this gets simulated over time instead. - if a train stops inside the neutral section announce zone, it has to start drawing power anyway to start back up, then cut power in the neutral section. this behavior is very hard to emulate with the current simulation engine. - if a sign announces a neutral section just before a switch, the announce zone is directional. getting this right probably means treating annonce signs as signals, and treat those as route dependant. This is a lot of work, and needs to wait until trains can react to signals (train sim v3). These hacks were a bad idea in the first place, and the features they were meant to implement will be a lot easier to implement once trains: - are simulated in a causal way - can react to signals
1 parent af41523 commit 1a87889

File tree

6 files changed

+15
-51
lines changed

6 files changed

+15
-51
lines changed

core/kt-osrd-rjs-parser/src/main/kotlin/fr/sncf/osrd/RawInfraRJSParser.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,10 @@ fun parseRJSInfra(rjsInfra: RJSInfra): RawInfra {
753753

754754
for (neutralSection in rjsInfra.neutralSections) {
755755
parseNeutralRanges(builder, false, neutralSection)
756-
parseNeutralRanges(builder, true, neutralSection)
756+
757+
// FIXME: the current implementation of neutral section announcements breaks
758+
// some use cases, see https://github.com/OpenRailAssociation/osrd/issues/7359
759+
// parseNeutralRanges(builder, true, neutralSection)
757760
}
758761

759762
for (speedSection in rjsInfra.speedSections) {

core/src/main/java/fr/sncf/osrd/train/RollingStock.java

+2-11
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,6 @@ public CurvesAndConditions mapTractiveEffortCurves(
233233
return new CurvesAndConditions(ImmutableRangeMap.copyOf(res), ImmutableRangeMap.copyOf(conditionsUsed));
234234
}
235235

236-
protected Range<Double> computeDeadSectionRange(Range<Double> neutralRange, Neutral n, Envelope maxEffortEnvelope) {
237-
var endRange = neutralRange.upperEndpoint();
238-
var finalSpeed = maxEffortEnvelope.interpolateSpeedLeftDir(endRange, 1);
239-
double additionalRange = finalSpeed * electricalPowerStartUpTime;
240-
if (n.lowerPantograph) {
241-
additionalRange += finalSpeed * raisePantographTime;
242-
}
243-
return Range.closed(neutralRange.lowerEndpoint(), neutralRange.upperEndpoint() + additionalRange);
244-
}
245-
246236
/**
247237
* Returns the tractive effort curves corresponding to the electrical conditions map with
248238
* neutral sections
@@ -268,7 +258,8 @@ public RangeMap<Double, TractiveEffortPoint[]> addNeutralSystemTimes(
268258
// estimate the distance during which the train will be coasting, due to having
269259
// respected the
270260
// neutral section
271-
var deadSectionRange = computeDeadSectionRange(elecCondEntry.getKey(), n, maxSpeedEnvelope);
261+
Range<Double> neutralRange = elecCondEntry.getKey();
262+
var deadSectionRange = Range.closed(neutralRange.lowerEndpoint(), neutralRange.upperEndpoint());
272263
var curveAndCondition = findTractiveEffortCurve(comfort, n);
273264
if (curveAndCondition.cond.mode == null) { // The train is effectively coasting
274265
newCurves.put(deadSectionRange, curveAndCondition.curve);

core/src/test/java/fr/sncf/osrd/api/StandaloneSimulationTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,8 @@ public void testElectrificationRangesInResultWithPowerRestriction() throws IOExc
628628

629629
ElectrificationUsage[] expected = {
630630
new ElectrifiedUsage("1500V", true, "O", false),
631+
// the C2 power restriction reduces the power class, so no electrical profile is found
632+
new ElectrifiedUsage("1500V", true, null, true),
631633
new NeutralUsage(true),
632634
new ElectrifiedUsage("25000V", true, "25000V", true),
633635
new ElectrifiedUsage("25000V", true, "20000V", true),

core/src/test/kotlin/fr/sncf/osrd/pathfinding/PathPropEndpointTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class PathPropEndpointTest : ApiTest() {
5050
assertEquals(
5151
parsed.electrifications,
5252
RangeValues(
53-
listOf(1800.meters, 1950.meters),
53+
listOf(1910.meters, 1950.meters),
5454
listOf(Electrified("1500V"), Neutral(true), Electrified("25000V"))
5555
)
5656
)

core/src/test/kotlin/fr/sncf/osrd/pathfinding/constraints/ElectrificationConstraintsTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class ElectrificationConstraintsTest {
5454
// section
5555
Arguments.of(
5656
1,
57-
mutableSetOf(Pathfinding.Range(Offset<Block>(0.meters), Offset(30.meters)))
57+
mutableSetOf(Pathfinding.Range(Offset<Block>(0.meters), Offset(140.meters)))
5858
), // Fully corresponding electrification ranges without dead
5959
// sections
6060
Arguments.of(2, HashSet<Any>())

core/src/test/kotlin/fr/sncf/osrd/sim_infra_adapter/EnvelopeTrainPathTest.kt

+5-37
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,8 @@ class EnvelopeTrainPathTest {
205205
putInElectrificationMapByPowerClass(
206206
expected,
207207
800.0,
208-
850.0,
209-
Electrified("1500V"),
210-
"A",
211-
false
212-
)
213-
putInElectrificationMapByPowerClass(
214-
expected,
215-
850.0,
216208
960.0,
217-
Neutral(true, Electrified("1500V"), true),
209+
Electrified("1500V"),
218210
"A",
219211
false
220212
)
@@ -310,16 +302,8 @@ class EnvelopeTrainPathTest {
310302
putInElectrificationMapByPowerClass(
311303
expectedElectrificationPowerClass1,
312304
2_600.0,
313-
2_900.0,
314-
Electrified("1500V"),
315-
"B",
316-
false
317-
)
318-
putInElectrificationMapByPowerClass(
319-
expectedElectrificationPowerClass1,
320-
2_900.0,
321305
2_910.0,
322-
Neutral(false, Electrified("1500V"), true),
306+
Electrified("1500V"),
323307
"B",
324308
false
325309
)
@@ -372,16 +356,8 @@ class EnvelopeTrainPathTest {
372356
putInElectrificationMapByPowerClass(
373357
expectedElectrificationPowerClass2,
374358
2_700.0,
375-
2_900.0,
376-
Electrified("1500V"),
377-
"C",
378-
false
379-
)
380-
putInElectrificationMapByPowerClass(
381-
expectedElectrificationPowerClass2,
382-
2_900.0,
383359
2_910.0,
384-
Neutral(false, Electrified("1500V"), true),
360+
Electrified("1500V"),
385361
"C",
386362
false
387363
)
@@ -422,11 +398,7 @@ class EnvelopeTrainPathTest {
422398
Direction.INCREASING,
423399
ImmutableRangeMap.Builder<Double, Electrification>()
424400
.put(Range.closedOpen(0.0, 300.0), NonElectrified())
425-
.put(Range.closedOpen(300.0, 1_350.0), Electrified("1500V"))
426-
.put(
427-
Range.closedOpen(1_350.0, 1_460.0),
428-
Neutral(true, Electrified("1500V"), true)
429-
)
401+
.put(Range.closedOpen(300.0, 1_460.0), Electrified("1500V"))
430402
.put(
431403
Range.closedOpen(1_460.0, 1_500.0),
432404
Neutral(true, Electrified("1500V"), false)
@@ -442,11 +414,7 @@ class EnvelopeTrainPathTest {
442414
ImmutableRangeMap.Builder<Double, Electrification>()
443415
.put(Range.closedOpen(0.0, 350.0), Electrified("25000V"))
444416
.put(Range.closedOpen(350.0, 450.0), NonElectrified())
445-
.put(Range.closedOpen(450.0, 1_450.0), Electrified("1500V"))
446-
.put(
447-
Range.closedOpen(1_450.0, 1_460.0),
448-
Neutral(false, Electrified("1500V"), true)
449-
)
417+
.put(Range.closedOpen(450.0, 1_460.0), Electrified("1500V"))
450418
.put(
451419
Range.closedOpen(1_460.0, 1_600.0),
452420
Neutral(false, Electrified("1500V"), false)

0 commit comments

Comments
 (0)