Skip to content

Commit f678685

Browse files
committed
core: stdcm: use spacing requirements instead of route occupancies
1 parent ba0a6dd commit f678685

File tree

24 files changed

+285
-277
lines changed

24 files changed

+285
-277
lines changed

core/kt-osrd-signaling/src/main/kotlin/fr/sncf/osrd/signaling/impl/BlockBuilder.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ internal fun internalBuildBlocks(
2727
// - if the signal is delimiting, stop and create the block (deduplicate it too)
2828
for (route in rawSignalingInfra.routes) {
2929
val routeEntryDet = rawSignalingInfra.getRouteEntry(route)
30-
val routeExitDet = rawSignalingInfra.getRouteExit(route)
30+
val routeExitDet = rawSignalingInfra.getBlockExit(route)
3131
val entrySignals = detectorEntrySignals[routeEntryDet]
3232
var currentBlocks = getInitPartialBlocks(sigModuleManager, rawSignalingInfra, loadedSignalInfra, entrySignals, routeEntryDet)
3333
// while inside the route, we maintain a list of currently active blocks.

core/kt-osrd-sim-infra/src/main/kotlin/fr/sncf/osrd/sim_infra/api/InterlockingInfra.kt

+7-5
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,22 @@ import fr.sncf.osrd.utils.units.OffsetList
1818
sealed interface Zone
1919
typealias ZoneId = StaticIdx<Zone>
2020

21+
@Suppress("INAPPLICABLE_JVM_NAME")
2122
interface LocationInfra : TrackNetworkInfra, TrackInfra, TrackProperties {
2223
val zones: StaticIdxSpace<Zone>
2324
fun getMovableElements(zone: ZoneId): StaticIdxSortedSet<TrackNode>
2425
fun getZoneBounds(zone: ZoneId): List<DirDetectorId>
26+
@JvmName("getZoneName")
27+
fun getZoneName(zone: ZoneId): String
28+
@JvmName("getZoneFromName")
29+
fun getZoneFromName(name: String): ZoneId
2530

2631
val detectors: StaticIdxSpace<Detector>
2732
fun getNextZone(dirDet: DirDetectorId): ZoneId?
2833
fun getPreviousZone(dirDet: DirDetectorId): ZoneId?
2934
fun getDetectorName(det: DetectorId): String?
3035
}
3136

32-
fun LocationInfra.getZoneName(zone: ZoneId): String {
33-
return "zone.${getZoneBounds(zone).map { "${getDetectorName(it.value)}:${it.direction}" }.minOf { it }}"
34-
}
35-
3637
fun LocationInfra.isBufferStop(detector: StaticIdx<Detector>): Boolean {
3738
return getNextZone(detector.increasing) == null || getNextZone(detector.decreasing) == null
3839
}
@@ -60,6 +61,7 @@ interface ReservationInfra : LocationInfra {
6061
fun getZonePathChunks(zonePath: ZonePathId): DirStaticIdxList<TrackChunk>
6162
}
6263

64+
@JvmName("getZonePathZone")
6365
fun ReservationInfra.getZonePathZone(zonePath: ZonePathId): ZoneId {
6466
return getNextZone(getZonePathEntry(zonePath))!!
6567
}
@@ -109,7 +111,7 @@ fun RoutingInfra.getRouteEntry(route: RouteId): DirDetectorId {
109111
}
110112

111113
@JvmName("getRouteExit")
112-
fun RoutingInfra.getRouteExit(route: RouteId): DirDetectorId {
114+
fun RoutingInfra.getBlockExit(route: RouteId): DirDetectorId {
113115
return getZonePathExit(getRoutePath(route).last())
114116
}
115117

core/kt-osrd-sim-infra/src/main/kotlin/fr/sncf/osrd/sim_infra/api/LoadedSignalingInfra.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,17 @@ interface BlockInfra {
5858
val blocks: StaticIdxSpace<Block>
5959
@JvmName("getBlockPath")
6060
fun getBlockPath(block: BlockId): StaticIdxList<ZonePath>
61+
@JvmName("getBlocksInZone")
62+
fun getBlocksInZone(zone: ZoneId): StaticIdxList<Block>
6163
fun getBlockSignals(block: BlockId): StaticIdxList<LogicalSignal>
6264
fun blockStartAtBufferStop(block: BlockId): Boolean
6365
fun blockStopAtBufferStop(block: BlockId): Boolean
6466

6567
fun getBlockSignalingSystem(block: BlockId): SignalingSystemId
66-
@JvmName("getBlocksAtDetector")
67-
fun getBlocksAtDetector(detector: DirDetectorId): StaticIdxList<Block>
68+
@JvmName("getBlocksStartingAtDetector")
69+
fun getBlocksStartingAtDetector(detector: DirDetectorId): StaticIdxList<Block>
70+
@JvmName("getBlocksEndingAtDetector")
71+
fun getBlocksEndingAtDetector(detector: DirDetectorId): StaticIdxList<Block>
6872
fun getBlocksAtSignal(signal: LogicalSignalId): StaticIdxList<Block>
6973
fun getSignalsPositions(block: BlockId): OffsetList<Block>
7074
@JvmName("getBlocksFromTrackChunk")

core/kt-osrd-sim-infra/src/main/kotlin/fr/sncf/osrd/sim_infra/impl/BlockInfraImpl.kt

+20-4
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,25 @@ class BlockInfraImpl(
4141
private val rawInfra: RawInfra,
4242
) : BlockInfra {
4343
private val blockEntryDetectorMap = IdxMap<DirDetectorId, MutableStaticIdxList<Block>>()
44+
private val blockExitDetectorMap = IdxMap<DirDetectorId, MutableStaticIdxList<Block>>()
4445
private val blockEntrySignalMap = IdxMap<LogicalSignalId, MutableStaticIdxList<Block>>()
4546
private val trackChunkToBlockMap = IdxMap<DirStaticIdx<TrackChunk>, MutableStaticIdxArraySet<Block>>()
4647
private val blockToTrackChunkMap = IdxMap<StaticIdx<Block>, MutableDirStaticIdxList<TrackChunk>>()
48+
private val zoneToBlockMap = IdxMap<ZoneId, MutableStaticIdxList<Block>>()
4749

4850
init {
4951
for (blockId in blockPool.space()) {
5052
val block = blockPool[blockId]
5153
val entryZonePath = block.path[0]
54+
val exitZonePath = block.path[block.path.size - 1]
5255

5356
// Update blockEntryDetectorMap
5457
val entryDirDet = rawInfra.getZonePathEntry(entryZonePath)
55-
val detList = blockEntryDetectorMap.getOrPut(entryDirDet) { mutableStaticIdxArrayListOf() }
56-
detList.add(blockId)
58+
val exitDirDet = rawInfra.getZonePathExit(exitZonePath)
59+
val entryDetList = blockEntryDetectorMap.getOrPut(entryDirDet) { mutableStaticIdxArrayListOf() }
60+
val exitDetList = blockExitDetectorMap.getOrPut(exitDirDet) { mutableStaticIdxArrayListOf() }
61+
entryDetList.add(blockId)
62+
exitDetList.add(blockId)
5763

5864
// Update blockEntrySignalMap
5965
if (!block.startAtBufferStop) {
@@ -62,7 +68,7 @@ class BlockInfraImpl(
6268
sigList.add(blockId)
6369
}
6470

65-
// Update trackChunkToBlockMap and blockToTrackChunkMap
71+
// Update trackChunkToBlockMap, blockToTrackChunkMap, and zoneToBlockMap
6672
for (zonePath in getBlockPath(blockId)) {
6773
val trackChunks = rawInfra.getZonePathChunks(zonePath)
6874
val blockTrackChunks = blockToTrackChunkMap.getOrPut(blockId) { mutableDirStaticIdxArrayListOf() }
@@ -71,6 +77,8 @@ class BlockInfraImpl(
7177
val chunkBlocks = trackChunkToBlockMap.getOrPut(trackChunk) { mutableStaticIdxArraySetOf() }
7278
chunkBlocks.add(blockId)
7379
}
80+
zoneToBlockMap.getOrPut(rawInfra.getZonePathZone(zonePath)) { mutableStaticIdxArrayListOf() }
81+
.add(blockId)
7482
}
7583
}
7684
}
@@ -82,6 +90,10 @@ class BlockInfraImpl(
8290
return blockPool[block].path
8391
}
8492

93+
override fun getBlocksInZone(zone: ZoneId): StaticIdxList<Block> {
94+
return zoneToBlockMap[zone]!!
95+
}
96+
8597
override fun getBlockSignals(block: BlockId): StaticIdxList<LogicalSignal> {
8698
return blockPool[block].signals
8799
}
@@ -98,10 +110,14 @@ class BlockInfraImpl(
98110
return loadedSignalInfra.getSignalingSystem(blockPool[block].signals[0])
99111
}
100112

101-
override fun getBlocksAtDetector(detector: DirDetectorId): StaticIdxList<Block> {
113+
override fun getBlocksStartingAtDetector(detector: DirDetectorId): StaticIdxList<Block> {
102114
return blockEntryDetectorMap[detector] ?: mutableStaticIdxArrayListOf()
103115
}
104116

117+
override fun getBlocksEndingAtDetector(detector: DirDetectorId): StaticIdxList<Block> {
118+
return blockExitDetectorMap[detector] ?: mutableStaticIdxArrayListOf()
119+
}
120+
105121
override fun getBlocksAtSignal(signal: LogicalSignalId): StaticIdxList<Block> {
106122
return blockEntrySignalMap[signal] ?: mutableStaticIdxArrayListOf()
107123
}

core/kt-osrd-sim-infra/src/main/kotlin/fr/sncf/osrd/sim_infra/impl/RawInfraBuilder.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ class RawInfraBuilderImpl : RawInfraBuilder {
447447
makeTrackNameMap(),
448448
makeRouteNameMap(),
449449
makeDetEntryToRouteMap(),
450-
makeDetExitToRouteMap()
450+
makeDetExitToRouteMap(),
451451
)
452452
}
453453

core/kt-osrd-sim-infra/src/main/kotlin/fr/sncf/osrd/sim_infra/impl/RawInfraImpl.kt

+23-3
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ class TrackChunkDescriptor(
9191
val speedSections: DirectionalMap<DistanceRangeMap<SpeedSection>>
9292
)
9393

94-
@JvmInline
95-
value class ZoneDescriptor(val movableElements: StaticIdxSortedSet<TrackNode>)
94+
class ZoneDescriptor(
95+
val movableElements: StaticIdxSortedSet<TrackNode>,
96+
var name: String = "",
97+
)
9698

9799
interface RouteDescriptor {
98100
val name: String?
@@ -186,7 +188,8 @@ class RawInfraImpl(
186188
val trackSectionNameMap: Map<String, TrackSectionId>,
187189
val routeNameMap: Map<String, RouteId>,
188190
val dirDetEntryToRouteMap: Map<DirDetectorId, StaticIdxList<Route>>,
189-
val dirDetExitToRouteMap: Map<DirDetectorId, StaticIdxList<Route>>
191+
val dirDetExitToRouteMap: Map<DirDetectorId, StaticIdxList<Route>>,
192+
val zoneNameMap: HashMap<String, ZoneId> = HashMap(),
190193
) : RawInfra {
191194
override val trackNodes: StaticIdxSpace<TrackNode>
192195
get() = trackNodePool.space()
@@ -307,6 +310,15 @@ class RawInfraImpl(
307310
zoneDetectors[prevZone]!!.add(detector.decreasing)
308311
}
309312

313+
// initialize zone names
314+
for (zone in zonePool) {
315+
val name = getZoneBounds(zone)
316+
.sortedBy { id -> id.index }
317+
.map { "${getDetectorName(it.value)}:${it.direction}" }
318+
zonePool[zone].name = "zone.${name}"
319+
zoneNameMap[zonePool[zone].name] = zone
320+
}
321+
310322
// initialize the physical signal to logical signal map
311323
for (physicalSignal in physicalSignalPool)
312324
for (child in physicalSignalPool[physicalSignal].logicalSignals)
@@ -360,6 +372,14 @@ class RawInfraImpl(
360372
return zoneDetectors[zone]!!
361373
}
362374

375+
override fun getZoneName(zone: ZoneId): String {
376+
return zonePool[zone].name
377+
}
378+
379+
override fun getZoneFromName(name: String): ZoneId {
380+
return zoneNameMap[name]!!
381+
}
382+
363383
override val detectors: StaticIdxSpace<Detector>
364384
get() = detectorPool.space()
365385

core/kt-osrd-sim-infra/src/main/kotlin/fr/sncf/osrd/sim_infra/utils/BlockRecovery.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private fun findRouteBlocks(
111111
// initialize with the BlockPathElements which are acceptable at the start of the route
112112
if (previousPaths == null) {
113113
val currentDet = signalingInfra.getZonePathEntry(routePath[0])
114-
val blocks = blockInfra.getBlocksAtDetector(currentDet)
114+
val blocks = blockInfra.getBlocksStartingAtDetector(currentDet)
115115
val blocksOnRoute = filterBlocks(allowedSignalingSystems, blockInfra, blocks, routePath, 0)
116116
for (block in blocksOnRoute) {
117117
val blockPath = blockInfra.getBlockPath(block)

core/kt-osrd-sncf-signaling/src/test/kotlin/fr/sncf/osrd/signaling/bal/TestBALtoBAL.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ class TestBALtoBAL {
117117
val loadedSignalInfra = simulator.loadSignals(infra)
118118
val blockInfra = simulator.buildBlocks(infra, loadedSignalInfra)
119119
val fullPath = mutableStaticIdxArrayListOf<Block>()
120-
fullPath.add(blockInfra.getBlocksAtDetector(detectorU.increasing).first())
121-
fullPath.add(blockInfra.getBlocksAtDetector(detectorV.increasing).first())
120+
fullPath.add(blockInfra.getBlocksStartingAtDetector(detectorU.increasing).first())
121+
fullPath.add(blockInfra.getBlocksStartingAtDetector(detectorV.increasing).first())
122122
val zoneStates = mutableListOf(ZoneStatus.CLEAR, ZoneStatus.CLEAR, ZoneStatus.CLEAR)
123123
val res = simulator.evaluate(infra, loadedSignalInfra, blockInfra, fullPath, 0, fullPath.size, zoneStates, ZoneStatus.INCOMPATIBLE)
124124
assertEquals("A", res[loadedSignalInfra.getLogicalSignals(signalV).first()]!!.getEnum("aspect"))

core/kt-osrd-sncf-signaling/src/test/kotlin/fr/sncf/osrd/signaling/bal/TestBAPRtoBAL.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ class TestBAPRtoBAL {
9898
val loadedSignalInfra = simulator.loadSignals(infra)
9999
val blockInfra = simulator.buildBlocks(infra, loadedSignalInfra)
100100
val fullPath = mutableStaticIdxArrayListOf<Block>()
101-
fullPath.add(blockInfra.getBlocksAtDetector(detectorW.increasing).first())
102-
fullPath.add(blockInfra.getBlocksAtDetector(detectorX.increasing).first())
103-
fullPath.add(blockInfra.getBlocksAtDetector(detectorY.increasing).first())
101+
fullPath.add(blockInfra.getBlocksStartingAtDetector(detectorW.increasing).first())
102+
fullPath.add(blockInfra.getBlocksStartingAtDetector(detectorX.increasing).first())
103+
fullPath.add(blockInfra.getBlocksStartingAtDetector(detectorY.increasing).first())
104104
val zoneStates = mutableListOf(ZoneStatus.CLEAR, ZoneStatus.CLEAR, ZoneStatus.INCOMPATIBLE)
105105
val res = simulator.evaluate(infra, loadedSignalInfra, blockInfra, fullPath, 0, fullPath.size, zoneStates, ZoneStatus.INCOMPATIBLE)
106106
val logicalSignals = listOf(signalm, signalM, signaln, signalN).map{loadedSignalInfra.getLogicalSignals(it).first()}

core/openapi.yaml

+2-12
Original file line numberDiff line numberDiff line change
@@ -754,20 +754,10 @@ components:
754754
example: "infraID"
755755
rolling_stocks:
756756
$ref: "#/components/schemas/RollingStock"
757-
route_occupancies:
757+
spacing_requirements:
758758
type: array
759759
items:
760-
type: object
761-
properties:
762-
id:
763-
type: string
764-
description: Route ID
765-
start_occupancy_time:
766-
type: number
767-
format: double
768-
end_occupancy_time:
769-
type: number
770-
format: double
760+
$ref: "#/components/schemas/SpacingRequirement"
771761
start_time:
772762
type: number
773763
format: double

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

+2-28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package fr.sncf.osrd.api.stdcm;
22

3-
import static fr.sncf.osrd.utils.KtToJavaConverter.toIntList;
4-
53
import fr.sncf.osrd.api.ExceptionHandler;
64
import fr.sncf.osrd.api.FullInfra;
75
import fr.sncf.osrd.api.InfraManager;
@@ -14,8 +12,6 @@
1412
import fr.sncf.osrd.reporting.exceptions.ErrorType;
1513
import fr.sncf.osrd.reporting.exceptions.OSRDError;
1614
import fr.sncf.osrd.reporting.warnings.DiagnosticRecorderImpl;
17-
import fr.sncf.osrd.sim_infra.api.InterlockingInfraKt;
18-
import fr.sncf.osrd.sim_infra.api.RawSignalingInfra;
1915
import fr.sncf.osrd.standalone_sim.ScheduleMetadataExtractor;
2016
import fr.sncf.osrd.standalone_sim.result.ResultEnvelopePoint;
2117
import fr.sncf.osrd.standalone_sim.result.StandaloneSimResult;
@@ -35,8 +31,6 @@
3531
import org.takes.rs.RsWithBody;
3632
import org.takes.rs.RsWithStatus;
3733
import java.util.ArrayList;
38-
import java.util.Collection;
39-
import java.util.HashSet;
4034
import java.util.List;
4135

4236
public class STDCMEndpoint implements Take {
@@ -70,7 +64,6 @@ public Response act(Request req) throws OSRDError {
7064
final var comfort = RJSRollingStockParser.parseComfort(request.comfort);
7165
final var steps = parseSteps(infra, request.steps);
7266
final String tag = request.speedLimitComposition;
73-
var occupancies = request.routeOccupancies;
7467
AllowanceValue standardAllowance = null;
7568
if (request.standardAllowance != null)
7669
standardAllowance = RJSStandaloneTrainScheduleParser.parseAllowanceValue(
@@ -81,11 +74,10 @@ public Response act(Request req) throws OSRDError {
8174

8275
// Build the unavailable space
8376
// temporary workaround, to remove with new signaling
84-
occupancies = addWarningOccupancies(infra.rawInfra(), occupancies);
8577
var unavailableSpace = UnavailableSpaceBuilder.computeUnavailableSpace(
8678
infra.rawInfra(),
8779
infra.blockInfra(),
88-
occupancies,
80+
request.spacingRequirements,
8981
rollingStock,
9082
request.gridMarginAfterSTDCM,
9183
request.gridMarginBeforeSTDCM
@@ -139,26 +131,8 @@ private static List<STDCMStep> parseSteps(FullInfra infra, List<STDCMRequest.STD
139131
.toList();
140132
}
141133

142-
/** The inputs only contains occupied blocks, we need to add the warning in the previous one (assuming BAL).
143-
* To be removed with new signaling. */
144-
private static Collection<STDCMRequest.RouteOccupancy> addWarningOccupancies(
145-
RawSignalingInfra rawInfra,
146-
Collection<STDCMRequest.RouteOccupancy> occupancies
147-
) {
148-
var warningOccupancies = new HashSet<>(occupancies);
149-
for (var occupancy : occupancies) {
150-
var route = rawInfra.getRouteFromName(occupancy.id);
151-
var previousRoutes = toIntList(rawInfra.getRoutesEndingAtDet(
152-
InterlockingInfraKt.getRouteEntry(rawInfra, route)));
153-
for (var previousRoute : previousRoutes)
154-
warningOccupancies.add(new STDCMRequest.RouteOccupancy(rawInfra.getRouteName(previousRoute),
155-
occupancy.startOccupancyTime, occupancy.endOccupancyTime));
156-
}
157-
return warningOccupancies;
158-
}
159-
160134
/** Generate a train schedule matching the envelope and rolling stock, with one stop at the end */
161-
private static StandaloneTrainSchedule makeTrainSchedule(
135+
public static StandaloneTrainSchedule makeTrainSchedule(
162136
double endPos,
163137
RollingStock rollingStock,
164138
RollingStock.Comfort comfort,

0 commit comments

Comments
 (0)