Skip to content

Commit

Permalink
core: sim-infra: move block recovery code to a separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
multun committed Jul 20, 2023
1 parent 0b6da4c commit 4cfabfa
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,124 +64,3 @@ interface BlockInfra {
fun getBlocksAtSignal(signal: LogicalSignalId): StaticIdxList<Block>
fun getSignalsPositions(block: BlockId): DistanceList
}

data class BlockPathElement(
val prev: BlockPathElement?,
val block: BlockId,
val route: RouteId,
val routeStartOffset: Int,
val routeEndOffset: Int,
)

fun BlockPathElement.toList() : StaticIdxList<Block> {
val res = mutableStaticIdxArrayListOf(this.block)
var cur = this.prev
while (cur != null) {
res.add(cur.block)
cur = cur.prev
}
return res.reversed()
}


fun filterBlocks(
allowedSignalingSystems: StaticIdxList<SignalingSystem>,
blockInfra: BlockInfra,
blocks: StaticIdxList<Block>,
routePath: StaticIdxList<ZonePath>,
routeOffset: Int,
): StaticIdxList<Block> {
val remainingZonePaths = routePath.size - routeOffset
val res = mutableStaticIdxArrayListOf<Block>()
blockLoop@ for (block in blocks) {
if (!allowedSignalingSystems.contains(blockInfra.getBlockSignalingSystem(block)))
continue
val blockPath = blockInfra.getBlockPath(block)
if (blockPath.size > remainingZonePaths)
continue
for (i in 0 until blockPath.size)
if (routePath[routeOffset + i] != blockPath[i])
continue@blockLoop
res.add(block)
}
return res
}


fun findRouteBlocks(
signalingInfra: RawSignalingInfra,
blockInfra: BlockInfra,
allowedSignalingSystems: StaticIdxList<SignalingSystem>,
previousPaths: List<BlockPathElement>?,
route: RouteId,
): List<BlockPathElement> {
val routePath = signalingInfra.getRoutePath(route)
var maxRouteEndOffset = 0
val incompletePaths = PriorityQueue<BlockPathElement>(Comparator.comparing { it.routeEndOffset })
val completePaths = mutableListOf<BlockPathElement>()

fun addPath(path: BlockPathElement) {
if (path.routeEndOffset == routePath.size) {
completePaths.add(path)
return
}
if (path.routeEndOffset > maxRouteEndOffset)
maxRouteEndOffset = path.routeEndOffset
incompletePaths.add(path)
}

fun findNextBlocks(prevPath: BlockPathElement, routeOffset: Int) {
val lastBlock = prevPath.block
if (blockInfra.blockStopAtBufferStop(lastBlock))
return
val blockSignals = blockInfra.getBlockSignals(lastBlock)
val curSignal = blockSignals[blockSignals.size - 1]
val blocks = blockInfra.getBlocksAtSignal(curSignal)
val blocksOnRoute = filterBlocks(allowedSignalingSystems, blockInfra, blocks, routePath, routeOffset)
for (block in blocksOnRoute) {
val blockSize = blockInfra.getBlockPath(block).size
addPath(BlockPathElement(prevPath, block, route, routeOffset, routeOffset + blockSize))
}
}

// initialize with the BlockPathElements which are acceptable at the start of the route
if (previousPaths == null) {
val currentDet = signalingInfra.getZonePathEntry(routePath[0])
val blocks = blockInfra.getBlocksAtDetector(currentDet)
val blocksOnRoute = filterBlocks(allowedSignalingSystems, blockInfra, blocks, routePath, 0)
for (block in blocksOnRoute) {
val blockPath = blockInfra.getBlockPath(block)
addPath(BlockPathElement(null, block, route, 0, blockPath.size))
}
} else {
for (prevPath in previousPaths)
findNextBlocks(prevPath, 0)
}

// for each block until the end of the route path,
// filter candidates which don't match and add new candidates
while (incompletePaths.isNotEmpty()) {
val candidatePath = incompletePaths.poll()!!
findNextBlocks(candidatePath, candidatePath.routeEndOffset)
}

assert(completePaths.isNotEmpty())

return completePaths
}


fun getRouteBlocks(
signalingInfra: RawSignalingInfra,
blockInfra: BlockInfra,
routes: StaticIdxList<Route>,
allowedSignalingSystems: StaticIdxList<SignalingSystem>
): List<StaticIdxList<Block>> {
var candidateBlocks: List<BlockPathElement>? = null

for (route in routes) {
val newCandidateBlocks = findRouteBlocks(signalingInfra, blockInfra, allowedSignalingSystems, candidateBlocks, route)
candidateBlocks = newCandidateBlocks
}
return candidateBlocks!!.map { it.toList() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package fr.sncf.osrd.sim_infra.utils

import fr.sncf.osrd.sim_infra.api.*
import fr.sncf.osrd.utils.indexing.StaticIdxList
import fr.sncf.osrd.utils.indexing.mutableStaticIdxArrayListOf
import java.util.*


data class BlockPathElement(
val prev: BlockPathElement?,
val block: BlockId,
// the index of the route in the path
val routeIndex: Int,
// the position of the block in the route
val blockRouteOffset: Int,
// the offset of the block in the route's zones
val routeStartZoneOffset: Int,
// always equal to routeStartZoneOffset + number of zones in the block
val routeEndZoneOffset: Int,
)

fun BlockPathElement.toList() : List<BlockPathElement> {
val res = mutableListOf(this)
var cur = this.prev
while (cur != null) {
res.add(cur)
cur = cur.prev
}
return res.reversed()
}

fun BlockPathElement.toBlockList() : StaticIdxList<Block> {
val res = mutableStaticIdxArrayListOf(this.block)
var cur = this.prev
while (cur != null) {
res.add(cur.block)
cur = cur.prev
}
return res.reversed()
}


private fun filterBlocks(
allowedSignalingSystems: StaticIdxList<SignalingSystem>,
blockInfra: BlockInfra,
blocks: StaticIdxList<Block>,
routePath: StaticIdxList<ZonePath>,
routeOffset: Int,
): StaticIdxList<Block> {
val remainingZonePaths = routePath.size - routeOffset
val res = mutableStaticIdxArrayListOf<Block>()
blockLoop@ for (block in blocks) {
if (!allowedSignalingSystems.contains(blockInfra.getBlockSignalingSystem(block)))
continue
val blockPath = blockInfra.getBlockPath(block)
if (blockPath.size > remainingZonePaths)
continue
for (i in 0 until blockPath.size)
if (routePath[routeOffset + i] != blockPath[i])
continue@blockLoop
res.add(block)
}
return res
}


private fun findRouteBlocks(
signalingInfra: RawSignalingInfra,
blockInfra: BlockInfra,
allowedSignalingSystems: StaticIdxList<SignalingSystem>,
previousPaths: List<BlockPathElement>?,
route: RouteId,
routeIndex: Int,
): List<BlockPathElement> {
val routePath = signalingInfra.getRoutePath(route)
var maxRouteEndOffset = 0
val incompletePaths = PriorityQueue<BlockPathElement>(Comparator.comparing { it.routeEndZoneOffset })
val completePaths = mutableListOf<BlockPathElement>()

fun addPath(path: BlockPathElement) {
if (path.routeEndZoneOffset == routePath.size) {
completePaths.add(path)
return
}
if (path.routeEndZoneOffset > maxRouteEndOffset)
maxRouteEndOffset = path.routeEndZoneOffset
incompletePaths.add(path)
}

fun findNextBlocks(prevPath: BlockPathElement, routeOffset: Int) {
val lastBlock = prevPath.block
if (blockInfra.blockStopAtBufferStop(lastBlock))
return
val blockSignals = blockInfra.getBlockSignals(lastBlock)
val curSignal = blockSignals[blockSignals.size - 1]
val blocks = blockInfra.getBlocksAtSignal(curSignal)
val blocksOnRoute = filterBlocks(allowedSignalingSystems, blockInfra, blocks, routePath, routeOffset)
for (block in blocksOnRoute) {
val blockSize = blockInfra.getBlockPath(block).size
addPath(BlockPathElement(
prevPath,
block, routeIndex,
prevPath.blockRouteOffset + 1,
routeOffset, routeOffset + blockSize
))
}
}

// initialize with the BlockPathElements which are acceptable at the start of the route
if (previousPaths == null) {
val currentDet = signalingInfra.getZonePathEntry(routePath[0])
val blocks = blockInfra.getBlocksAtDetector(currentDet)
val blocksOnRoute = filterBlocks(allowedSignalingSystems, blockInfra, blocks, routePath, 0)
for (block in blocksOnRoute) {
val blockPath = blockInfra.getBlockPath(block)
addPath(BlockPathElement(null, block, routeIndex, 0, 0, blockPath.size))
}
} else {
for (prevPath in previousPaths)
findNextBlocks(prevPath, 0)
}

// for each block until the end of the route path,
// filter candidates which don't match and add new candidates
while (incompletePaths.isNotEmpty()) {
val candidatePath = incompletePaths.poll()!!
findNextBlocks(candidatePath, candidatePath.routeEndZoneOffset)
}

assert(completePaths.isNotEmpty())

return completePaths
}

/** Recovers possible block paths from a route path */
fun recoverBlocks(
sigInfra: RawSignalingInfra,
blockInfra: BlockInfra,
routes: StaticIdxList<Route>,
allowedSigSystems: StaticIdxList<SignalingSystem>
): List<BlockPathElement> {
var candidates: List<BlockPathElement>? = null

for (routeIndex in 0 until routes.size) {
val route = routes[routeIndex]
val newCandidates = findRouteBlocks(sigInfra, blockInfra, allowedSigSystems, candidates, route, routeIndex)
candidates = newCandidates
}
return candidates!!
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import fr.sncf.osrd.infra_state.api.TrainPath
import fr.sncf.osrd.signaling.SignalingSimulator
import fr.sncf.osrd.signaling.ZoneStatus
import fr.sncf.osrd.sim_infra.api.*
import fr.sncf.osrd.sim_infra.utils.BlockPathElement
import fr.sncf.osrd.sim_infra_adapter.SimInfraAdapter
import fr.sncf.osrd.standalone_sim.result.*
import fr.sncf.osrd.standalone_sim.result.ResultTrain.SpacingRequirement
import fr.sncf.osrd.sim_infra.utils.recoverBlocks
import fr.sncf.osrd.sim_infra.utils.toList
import fr.sncf.osrd.train.StandaloneTrainSchedule
import fr.sncf.osrd.utils.CurveSimplification
import fr.sncf.osrd.utils.indexing.*
Expand All @@ -24,6 +27,26 @@ import kotlin.math.abs
import kotlin.math.max


// TODO: run pathfinding on blocks
private fun recoverBlockPath(
simulator: SignalingSimulator,
fullInfra: FullInfra,
routePath: StaticIdxList<Route>,
): List<BlockPathElement> {
// TODO: the allowed signaling systems should depend on the type of train
val sigSystemManager = simulator.sigModuleManager
val bal = sigSystemManager.findSignalingSystem("BAL")
val bapr = sigSystemManager.findSignalingSystem("BAPR")
val tvm = sigSystemManager.findSignalingSystem("TVM")

val blockPaths = recoverBlocks(
fullInfra.rawInfra, fullInfra.blockInfra, routePath, mutableStaticIdxArrayListOf(bal, bapr, tvm)
)
assert(blockPaths.isNotEmpty())
return blockPaths[0].toList() // TODO: have a better way to choose the block path
}


/** Use an already computed envelope to extract various metadata about a trip. */
fun run(
envelope: Envelope, trainPath: TrainPath, schedule: StandaloneTrainSchedule, fullInfra: FullInfra
Expand All @@ -35,24 +58,18 @@ fun run(
val blockInfra = fullInfra.blockInfra;
val simulator = fullInfra.signalingSimulator;

// TODO: the allowed signaling systems should be dependant on the type of train
val sigSystemManager = simulator.sigModuleManager
val bal = sigSystemManager.findSignalingSystem("BAL")
val bapr = sigSystemManager.findSignalingSystem("BAPR")
val tvm = sigSystemManager.findSignalingSystem("TVM")

// Get the route path
// TODO: do it in the pathfinding
val routes = MutableStaticIdxArrayList<Route>()
// get a new generation route path
val routePath = MutableStaticIdxArrayList<Route>()
for (javaRoute in trainPath.routePath) {
val route = rawInfra.routeMap[javaRoute.element.infraRoute]!!
routes.add(route)
val route = fullInfra.rawInfra.routeMap[javaRoute.element.infraRoute]!!
routePath.add(route)
}
val blockPaths = getRouteBlocks(
rawInfra, blockInfra, routes, mutableStaticIdxArrayListOf(bal, bapr, tvm)
)
assert(blockPaths.isNotEmpty())
val blockPath = blockPaths[0] // TODO: have a better way to choose the block path

// recover blocks from the route paths
val detailedBlockPath = recoverBlockPath(simulator, fullInfra, routePath)
val blockPath = mutableStaticIdxArrayListOf<Block>()
for (block in detailedBlockPath)
blockPath.add(block.block)

// Compute speeds, head and tail positions
val envelopeWithStops = EnvelopeStopWrapper(envelope, schedule.stops)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package fr.sncf.osrd.standalone_sim

import fr.sncf.osrd.api.FullInfra
import fr.sncf.osrd.api.SignalProjectionEndpoint
import fr.sncf.osrd.api.SignalProjectionEndpoint.SignalProjectionResult
import fr.sncf.osrd.envelope.Envelope
import fr.sncf.osrd.infra_state.api.TrainPath
import fr.sncf.osrd.reporting.exceptions.OSRDError
import fr.sncf.osrd.signaling.SignalingSimulator
import fr.sncf.osrd.signaling.ZoneStatus
import fr.sncf.osrd.sim_infra.api.*
import fr.sncf.osrd.sim_infra.utils.recoverBlocks
import fr.sncf.osrd.sim_infra.utils.toBlockList
import fr.sncf.osrd.sim_infra_adapter.SimInfraAdapter
import fr.sncf.osrd.standalone_sim.result.ResultTrain.SignalSighting
import fr.sncf.osrd.standalone_sim.result.ResultTrain.ZoneUpdate
Expand Down Expand Up @@ -46,11 +46,11 @@ fun project(
routes.add(route)
}

val blockPaths = getRouteBlocks(
val blockPaths = recoverBlocks(
rawInfra, blockInfra, routes, mutableStaticIdxArrayListOf(bal, bapr, tvm)
)
assert(blockPaths.isNotEmpty())
val blockPath = blockPaths[0] // TODO: have a better way to choose the block path
val blockPath = blockPaths[0].toBlockList() // TODO: have a better way to choose the block path

val zoneMap = mutableMapOf<String, Int>()
var zoneCount = 0
Expand Down

0 comments on commit 4cfabfa

Please sign in to comment.