Skip to content

Commit

Permalink
core: driver-behavior: only apply to BAL and BAPR
Browse files Browse the repository at this point in the history
Signed-off-by: Eloi Charpentier <[email protected]>
  • Loading branch information
eckter committed Feb 12, 2025
1 parent c319133 commit aebb462
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 33 deletions.
16 changes: 13 additions & 3 deletions core/envelope-sim/src/main/kotlin/fr/sncf/osrd/DriverBehaviour.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,33 @@ import fr.sncf.osrd.envelope.Envelope
import fr.sncf.osrd.envelope.MRSPEnvelopeBuilder
import fr.sncf.osrd.envelope.part.EnvelopePart
import fr.sncf.osrd.envelope_sim.EnvelopeProfile
import fr.sncf.osrd.utils.DistanceRangeMap
import fr.sncf.osrd.utils.distanceRangeMapOf
import fr.sncf.osrd.utils.units.meters
import kotlin.math.max
import kotlin.math.min

data class DriverBehaviour(
val acceleratingPostponementOffset: Double = 50.0,
val brakingAnticipationOffset: Double = 100.0,
val signalingSystems: List<String> = listOf("BAL", "BAPR")
) {
/** Applies the driver behavior to the MRSP, adding reaction time for MRSP changes */
fun applyToMRSP(mrsp: Envelope): Envelope {
fun applyToMRSP(
mrsp: Envelope,
optSignalingSystemRanges: DistanceRangeMap<String>? = null
): Envelope {
val signalingSystemRanges = optSignalingSystemRanges ?: distanceRangeMapOf()
val builder = MRSPEnvelopeBuilder()
val totalLength = mrsp.totalDistance
for (part in mrsp) {
var begin = part.beginPos
var end = part.endPos
// compute driver behaviour offsets
begin -= this.brakingAnticipationOffset
end += this.acceleratingPostponementOffset
if (signalingSystems.contains(signalingSystemRanges.get(begin.meters) ?: ""))
begin -= this.brakingAnticipationOffset
if (signalingSystems.contains(signalingSystemRanges.get(end.meters) ?: ""))
end += this.acceleratingPostponementOffset
begin = max(0.0, begin)
end = min(totalLength, end)
val speed = part.maxSpeed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,16 @@ interface DistanceRangeSet : Iterable<DistanceRangeSet.RangeSetEntry> {
fun distanceRangeSetOf(): DistanceRangeSet {
return DistanceRangeSetImpl()
}

/**
* Create a range set from a range map, with values set where the predicate matches the map value.
*/
fun <T> DistanceRangeMap<T>.mapToRangeSet(f: (T) -> Boolean): DistanceRangeSet {
val res = distanceRangeSetOf()
for (entry in this) {
if (f(entry.value)) {
res.put(entry.lower, entry.upper)
}
}
return res
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static StandaloneSimResult run(
// MRSP & SpeedLimits
var mrsp = computeMRSP(trainPath, rollingStock, true, trainSchedule.tag, null, null, true);
var speedLimits = computeMRSP(trainPath, rollingStock, false, trainSchedule.tag, null, null, true);
mrsp = driverBehaviour.applyToMRSP(mrsp);
mrsp = driverBehaviour.applyToMRSP(mrsp, null);
cacheSpeedLimits.put(trainSchedule, ResultEnvelopePoint.from(speedLimits));

// Context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import fr.sncf.osrd.standalone_sim.result.ElectrificationRange.ElectrificationUs
import fr.sncf.osrd.standalone_sim.result.ElectrificationRange.ElectrificationUsage.ElectrifiedUsage
import fr.sncf.osrd.train.RollingStock
import fr.sncf.osrd.utils.DistanceRangeMap
import fr.sncf.osrd.utils.distanceRangeMapOf
import fr.sncf.osrd.utils.indexing.StaticIdxList
import fr.sncf.osrd.utils.units.Distance
import fr.sncf.osrd.utils.units.Offset
Expand Down Expand Up @@ -70,6 +71,7 @@ fun runStandaloneSimulation(
driverBehaviour: DriverBehaviour = DriverBehaviour()
): SimulationSuccess {
if (chunkPath.length == 0.meters) throw OSRDError(ZeroLengthPath)
val signalingRanges = buildSignalingRanges(infra, blockPath, chunkPath)
// MRSP & SpeedLimits
val safetySpeedRanges = makeSafetySpeedRanges(infra, chunkPath, routes, schedule)
var mrsp =
Expand All @@ -82,7 +84,7 @@ fun runStandaloneSimulation(
safetySpeedRanges,
useInfraSpeedLimits
)
mrsp = driverBehaviour.applyToMRSP(mrsp)
mrsp = driverBehaviour.applyToMRSP(mrsp, signalingRanges)
// We don't use speed safety ranges in the MRSP displayed in the front
// (just like we don't add the train length)
val speedLimits =
Expand Down Expand Up @@ -115,7 +117,7 @@ fun runStandaloneSimulation(
envelopeSimPath,
timeStep,
curvesAndConditions.curves,
makeETCSContext(rollingStock, infra, chunkPath, routes, blockPath)
makeETCSContext(rollingStock, infra, chunkPath, routes, signalingRanges)
)

// Max speed envelope
Expand Down Expand Up @@ -190,6 +192,33 @@ fun runStandaloneSimulation(
)
}

/** Returns the ranges where each signaling system is encountered, as travelled path offsets. */
fun buildSignalingRanges(
infra: FullInfra,
blockPath: StaticIdxList<Block>,
chunkPath: ChunkPath
): DistanceRangeMap<String> {
val blockInfra = infra.blockInfra
var blockStartOffset =
Offset<TravelledPath>(
trainPathBlockOffset(infra.rawInfra, infra.blockInfra, blockPath, chunkPath) * -1.0
)
val res = distanceRangeMapOf<String>()
for (blockId in blockPath) {
val blockLength = blockInfra.getBlockLength(blockId)
val blockEndOffset = blockStartOffset + blockLength.distance
val sigSystem = blockInfra.getBlockSignalingSystem(blockId)
val name = infra.signalingSimulator.sigModuleManager.getName(sigSystem)
res.put(
Distance.max(blockStartOffset.distance, Distance.ZERO),
Distance.min(blockEndOffset.distance, chunkPath.length),
name,
)
blockStartOffset += blockLength.distance
}
return res
}

fun makeElectricalProfiles(
electrificationRanges: List<ElectrificationRange>
): RangeValues<ElectricalProfileValue> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import fr.sncf.osrd.sim_infra.impl.ChunkPath
import fr.sncf.osrd.sim_infra.utils.getNextTrackSections
import fr.sncf.osrd.train.RollingStock
import fr.sncf.osrd.utils.Direction
import fr.sncf.osrd.utils.distanceRangeSetOf
import fr.sncf.osrd.utils.DistanceRangeMap
import fr.sncf.osrd.utils.indexing.DirStaticIdx
import fr.sncf.osrd.utils.indexing.StaticIdxList
import fr.sncf.osrd.utils.units.Distance
import fr.sncf.osrd.utils.mapToRangeSet
import fr.sncf.osrd.utils.units.Offset

/** Build the ETCS context, if relevant. */
Expand All @@ -20,31 +20,9 @@ fun makeETCSContext(
infra: FullInfra,
chunkPath: ChunkPath,
routePath: StaticIdxList<Route>,
blockPath: StaticIdxList<Block>
signalingRanges: DistanceRangeMap<String>,
): EnvelopeSimContext.ETCSContext? {
val blockInfra = infra.blockInfra
val etcsRanges = distanceRangeSetOf()
val etcsLevel2 =
infra.signalingSimulator.sigModuleManager.findSignalingSystemOrThrow(ETCS_LEVEL2.id)
var blockStartOffset =
Offset<TravelledPath>(
trainPathBlockOffset(infra.rawInfra, infra.blockInfra, blockPath, chunkPath) * -1.0
)
for (blockId in blockPath) {
val blockLength = blockInfra.getBlockLength(blockId)
val blockEndOffset = blockStartOffset + blockLength.distance
if (
blockInfra.getBlockSignalingSystem(blockId) == etcsLevel2 &&
chunkPath.length >= blockStartOffset.distance &&
blockEndOffset.distance >= Distance.ZERO
) {
etcsRanges.put(
Distance.max(blockStartOffset.distance, Distance.ZERO),
Distance.min(blockEndOffset.distance, chunkPath.length)
)
}
blockStartOffset += blockLength.distance
}
val etcsRanges = signalingRanges.mapToRangeSet { it == ETCS_LEVEL2.id }

if (etcsRanges.asList().isEmpty()) {
return null
Expand Down
10 changes: 9 additions & 1 deletion core/src/test/java/fr/sncf/osrd/DriverBehaviourTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import fr.sncf.osrd.api.pathfinding.makePathProps
import fr.sncf.osrd.envelope_sim_infra.computeMRSP
import fr.sncf.osrd.sim_infra.api.PathProperties
import fr.sncf.osrd.train.TestTrains
import fr.sncf.osrd.utils.DistanceRangeMap
import fr.sncf.osrd.utils.DummyInfra
import fr.sncf.osrd.utils.distanceRangeMapOf
import fr.sncf.osrd.utils.units.Length
import fr.sncf.osrd.utils.units.meters
import org.junit.jupiter.api.Assertions
Expand All @@ -24,7 +26,13 @@ class DriverBehaviourTest {
val testRollingStock = TestTrains.VERY_SHORT_FAST_TRAIN
val driverBehaviour = DriverBehaviour(2.0, 3.0)
var mrsp = computeMRSP(path, testRollingStock, true, null, null)
mrsp = driverBehaviour.applyToMRSP(mrsp)
mrsp =
driverBehaviour.applyToMRSP(
mrsp,
distanceRangeMapOf(
DistanceRangeMap.RangeMapEntry(0.meters, path.getLength(), "BAL")
)
)
Assertions.assertEquals(20.0, mrsp.interpolateSpeedRightDir(0.0, 1.0))
Assertions.assertEquals(10.0, mrsp.interpolateSpeedRightDir((100 - 3).toDouble(), 1.0))
Assertions.assertEquals(
Expand Down

0 comments on commit aebb462

Please sign in to comment.