Skip to content

Commit 1b0ee8f

Browse files
Sh099078Khoyo
andcommitted
handle multiple consists per train schedule
Co-authored-by: Younes Khoudli <younes.khoudli@epita.fr> Signed-off-by: Loup Federico <16464925+Sh099078@users.noreply.github.com>
1 parent 5df99d8 commit 1b0ee8f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1212
-308
lines changed

core/envelope-sim/src/main/java/fr/sncf/osrd/envelope/EnvelopeBuilder.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,13 @@ class EnvelopeBuilder {
4747
}
4848
}
4949
}
50+
51+
fun concatenateAndShiftEnvelopes(envelopes: List<Envelope>): Envelope {
52+
var currentOffset = 0.0
53+
val envelopeParts = mutableListOf<EnvelopePart>()
54+
for (envelope in envelopes) {
55+
envelopeParts.addAll(envelope.map { it.copyAndShift(currentOffset) })
56+
currentOffset += envelope.endPos
57+
}
58+
return Envelope(envelopeParts.toTypedArray())
59+
}

core/envelope-sim/src/main/java/fr/sncf/osrd/envelope/part/EnvelopePart.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,16 +521,18 @@ class EnvelopePart(
521521
*/
522522
fun copyAndShift(
523523
positionDelta: Double,
524-
minPosition: Double,
525-
maxPosition: Double,
524+
minPosition: Double? = null,
525+
maxPosition: Double? = null,
526526
): EnvelopePart {
527527
val newPositions = DoubleArrayList()
528528
val newSpeeds = DoubleArrayList()
529529
val newTimeDeltas = DoubleArrayList()
530530
newPositions.add(positions[0] + positionDelta)
531531
newSpeeds.add(speeds[0])
532532
for (i in 1 until positions.size) {
533-
val p = max(minPosition, min(maxPosition, positions[i] + positionDelta))
533+
var p = positions[i] + positionDelta
534+
if (minPosition != null) p = max(minPosition, p)
535+
if (maxPosition != null) p = min(maxPosition, p)
534536
if (newPositions.last().value != p) {
535537
// Positions that are an epsilon away may be overlapping after the shift, we only
536538
// add the distinct ones

core/src/main/java/fr/sncf/osrd/cli/BenchSTDCM.kt

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,24 +175,39 @@ class BenchSTDCM : CliCommand {
175175
try {
176176
val temporarySpeedLimitManager =
177177
buildTemporarySpeedLimitManager(infra, request.temporarySpeedLimits)
178-
val rollingStock =
179-
parseRawRollingStock(
180-
request.consistSchedule.values[0].physicsConsist,
181-
request.consistSchedule.values[0].loadingGaugeType,
182-
request.consistSchedule.values[0].supportedSignalingSystems.filter {
183-
// Ignoring ETCS as it is not (yet) supported for STDCM
184-
it != ETCS_LEVEL2.id
185-
},
178+
val consistConfigurations =
179+
request.consistSchedule.values.map { it ->
180+
it.copy(
181+
supportedSignalingSystems =
182+
it.supportedSignalingSystems.filter {
183+
// Ignoring ETCS as it is not (yet) supported for
184+
it != ETCS_LEVEL2.id
185+
}
186+
)
187+
}
188+
val requestConsistSchedule =
189+
request.consistSchedule.copy(values = consistConfigurations)
190+
val allowedTrackSections =
191+
parseTrackSectionIds(infra, request.allowedTrackSections)
192+
val consistSchedules =
193+
ConsistSchedule(
194+
requestConsistSchedule,
195+
infra,
196+
allowedTrackSections,
197+
request.pathItems.size,
186198
)
187199
val steps =
188-
parseSteps(infra, request.pathItems, request.startTime, rollingStock.length)
200+
parseSteps(
201+
infra,
202+
request.pathItems,
203+
request.startTime,
204+
consistSchedules.rollingStocks.map { it.length },
205+
)
189206
val requirements = getRequirements(request, infra, cacheManager)
190-
val allowedTrackSections =
191-
parseTrackSectionIds(infra, request.allowedTrackSections)
192207
path =
193208
findPath(
194209
infra,
195-
rollingStock,
210+
consistSchedules,
196211
request.comfort,
197212
0.0,
198213
steps,

core/src/main/kotlin/fr/sncf/osrd/api/CommonSchemas.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import fr.sncf.osrd.railjson.schema.common.graph.EdgeDirection
66
import fr.sncf.osrd.sim_infra.api.TrackSection
77
import fr.sncf.osrd.utils.DistanceRangeMap
88
import fr.sncf.osrd.utils.distanceRangeMapOf
9+
import fr.sncf.osrd.utils.units.Distance
910
import fr.sncf.osrd.utils.units.Offset
1011
import fr.sncf.osrd.utils.units.TimeDelta
12+
import fr.sncf.osrd.utils.units.meters
1113

1214
data class DirectionalTrackRange(
1315
@Json(name = "track_section") val trackSection: String,
@@ -51,6 +53,16 @@ data class RangeValues<valueT>(
5153
}
5254
return distanceRangeMapOf(rangeMapEntries)
5355
}
56+
57+
fun shifted(distance: Distance): RangeValues<valueT> {
58+
return this.copy(
59+
internalBoundaries =
60+
this.internalBoundaries.map {
61+
require(it + distance > Offset(0.meters))
62+
it + distance
63+
}
64+
)
65+
}
5466
}
5567

5668
class TrackLocation(val track: String, val offset: Offset<TrackSection>)

core/src/main/kotlin/fr/sncf/osrd/api/RollingStockParser.kt

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
package fr.sncf.osrd.api
22

33
import fr.sncf.osrd.api.standalone_sim.PhysicsConsistModel
4+
import fr.sncf.osrd.api.stdcm.RequestConsistSchedule
5+
import fr.sncf.osrd.envelope_sim.PhysicsRollingStock
46
import fr.sncf.osrd.envelope_sim.PhysicsRollingStock.TractiveEffortPoint
57
import fr.sncf.osrd.envelope_sim.etcs.toEtcsBrakeParams
8+
import fr.sncf.osrd.graph.PathfindingConstraint
9+
import fr.sncf.osrd.pathfinding.constraints.CachedBlockConstraintCombiner
10+
import fr.sncf.osrd.pathfinding.constraints.initConstraints
611
import fr.sncf.osrd.railjson.schema.rollingstock.RJSEffortCurves.*
712
import fr.sncf.osrd.railjson.schema.rollingstock.RJSLoadingGaugeType
813
import fr.sncf.osrd.railjson.schema.rollingstock.RJSRollingResistance
914
import fr.sncf.osrd.railjson.schema.rollingstock.RJSRollingResistance.Davis
1015
import fr.sncf.osrd.reporting.exceptions.ErrorType
1116
import fr.sncf.osrd.reporting.exceptions.OSRDError
17+
import fr.sncf.osrd.sim_infra.api.TrackSectionId
1218
import fr.sncf.osrd.train.RollingStock
1319
import fr.sncf.osrd.train.RollingStock.*
20+
import kotlin.collections.get
1421

1522
/** Parse the rolling stock model into something the backend can work with */
1623
fun parseRawRollingStock(
@@ -60,6 +67,101 @@ fun parseRawRollingStock(
6067
)
6168
}
6269

70+
/**
71+
* Associates a list of rolling stocks with their related pathfinding constraints. This class
72+
* provides two ways to be built:
73+
* - From a list of STDCM query inputs.
74+
* - From a list of rolling stocks and their pathfinding constraints. This approach is mostly useful
75+
* for testing purposes.
76+
*/
77+
data class ConsistSchedule(
78+
val rollingStocks: List<PhysicsRollingStock>,
79+
val constraints: List<PathfindingConstraint>?,
80+
) {
81+
init {
82+
require(!rollingStocks.isEmpty())
83+
require(constraints == null || rollingStocks.size == constraints.size)
84+
}
85+
86+
companion object {
87+
operator fun invoke(
88+
consistSchedule: RequestConsistSchedule,
89+
infra: FullInfra,
90+
allowedTrackSections: Set<TrackSectionId>? = null,
91+
totalSteps: Int,
92+
): ConsistSchedule {
93+
val boundaries = consistSchedule.boundaries
94+
val rollingStocks =
95+
consistSchedule.values.map {
96+
parseRawRollingStock(
97+
it.physicsConsist,
98+
it.loadingGaugeType,
99+
it.supportedSignalingSystems,
100+
)
101+
}
102+
return ConsistSchedule(
103+
rollingStocks,
104+
boundaries,
105+
infra,
106+
allowedTrackSections,
107+
totalSteps,
108+
)
109+
}
110+
111+
operator fun invoke(
112+
rollingStocks: List<RollingStock>,
113+
boundaries: List<Int>,
114+
infra: FullInfra,
115+
allowedTrackSections: Set<TrackSectionId>? = null,
116+
totalSteps: Int,
117+
): ConsistSchedule {
118+
// Input validation:
119+
when {
120+
(rollingStocks.size != boundaries.size + 1) -> {
121+
throw OSRDError(ErrorType.InvalidSTDCMInputs)
122+
.withContext(
123+
"cause",
124+
"${boundaries.size} boundaries and ${rollingStocks.size} consist configurations provided. There should be n-1 boundaries for n consist configurations",
125+
)
126+
}
127+
(!boundaries.zipWithNext().all { (a, b) -> a < b }) -> {
128+
throw OSRDError(ErrorType.InvalidSTDCMInputs)
129+
.withContext(
130+
"cause",
131+
"Consist change boundaries are not strictly increasing",
132+
)
133+
}
134+
(!(boundaries.isEmpty() ||
135+
(boundaries.first() != 0 && boundaries.last() != totalSteps - 1))) -> {
136+
throw OSRDError(ErrorType.InvalidSTDCMInputs)
137+
.withContext(
138+
"cause",
139+
"Consist change specified on the first or last step of the path",
140+
)
141+
}
142+
}
143+
144+
// Build the rolling stock and constraint for each step:
145+
val rollingStocksPerStep = mutableListOf<RollingStock>()
146+
val constraints = mutableListOf<PathfindingConstraint>()
147+
var previousBoundary = 0
148+
for ((index, rollingStock) in rollingStocks.withIndex()) {
149+
val boundary = boundaries.getOrNull(index) ?: totalSteps
150+
val constraint =
151+
CachedBlockConstraintCombiner(
152+
initConstraints(infra, rollingStock, allowedTrackSections)
153+
)
154+
(previousBoundary..<boundary).forEach { _ ->
155+
rollingStocksPerStep.add(rollingStock)
156+
constraints.add(constraint)
157+
}
158+
previousBoundary = boundary
159+
}
160+
return ConsistSchedule(rollingStocksPerStep, constraints)
161+
}
162+
}
163+
}
164+
63165
private fun parseRollingResistance(rjsRollingResistance: RJSRollingResistance?): Davis {
64166
if (rjsRollingResistance == null)
65167
throw OSRDError.newMissingRollingStockFieldError("rolling_resistance")

core/src/main/kotlin/fr/sncf/osrd/api/standalone_sim/SimulationRequest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ enum class AllowanceDistribution {
5858
}
5959
}
6060

61-
class PhysicsConsistModel(
61+
data class PhysicsConsistModel(
6262
@Json(name = "effort_curves") val effortCurves: EffortCurve,
6363
@Json(name = "base_power_class") val basePowerClass: String?,
6464
val length: Length<RollingStock>,

0 commit comments

Comments
 (0)