@@ -36,6 +36,9 @@ class STDCMSimulations {
36
36
private var simulatedEnvelopes: HashMap <BlockSimulationParameters , SoftReference <Envelope >? > =
37
37
HashMap ()
38
38
39
+ // Used to log how many simulations failed (to log it once at the end of the processing)
40
+ private var nFailedSimulation = 0
41
+
39
42
/* *
40
43
* Returns the corresponding envelope if the block's envelope has already been computed in
41
44
* simulatedEnvelopes, otherwise computes the matching envelope and adds it to the STDCMGraph.
@@ -66,6 +69,67 @@ class STDCMSimulations {
66
69
simulatedEnvelopes[blockParams] = SoftReference (simulatedEnvelope)
67
70
return simulatedEnvelope
68
71
}
72
+
73
+ /* *
74
+ * Returns an envelope matching the given block. The envelope time starts when the train enters
75
+ * the block. stopPosition specifies the position at which the train should stop, may be null
76
+ * (no stop).
77
+ *
78
+ * Note: there are some approximations made here as we only "see" the tracks on the given
79
+ * blocks. We are missing slopes and speed limits from earlier in the path.
80
+ */
81
+ fun simulateBlock (
82
+ rawInfra : RawSignalingInfra ,
83
+ infraExplorer : InfraExplorer ,
84
+ initialSpeed : Double ,
85
+ start : Offset <Block >,
86
+ rollingStock : RollingStock ,
87
+ comfort : Comfort ? ,
88
+ timeStep : Double ,
89
+ stopPosition : Offset <Block >? ,
90
+ trainTag : String?
91
+ ): Envelope ? {
92
+ if (stopPosition != null && stopPosition == Offset <Block >(0 .meters))
93
+ return makeSinglePointEnvelope(0.0 )
94
+ val blockLength = infraExplorer.getCurrentBlockLength()
95
+ if (start >= blockLength) return makeSinglePointEnvelope(initialSpeed)
96
+ var stops = doubleArrayOf()
97
+ var simLength = blockLength.distance - start.distance
98
+ if (stopPosition != null ) {
99
+ stops = doubleArrayOf(stopPosition.distance.meters)
100
+ simLength = Distance .min(simLength, stopPosition.distance)
101
+ }
102
+ val path = infraExplorer.getCurrentEdgePathProperties(start, simLength)
103
+ val envelopePath = EnvelopeTrainPath .from(rawInfra, path)
104
+ val context = build(rollingStock, envelopePath, timeStep, comfort)
105
+ val mrsp = computeMRSP(path, rollingStock, false , trainTag)
106
+ return try {
107
+ val maxSpeedEnvelope = MaxSpeedEnvelope .from(context, stops, mrsp)
108
+ MaxEffortEnvelope .from(context, initialSpeed, maxSpeedEnvelope)
109
+ } catch (e: OSRDError ) {
110
+ // The train can't reach its destination, for example because of high slopes
111
+ if (nFailedSimulation == 0 ) {
112
+ // We only log the first one (to get an actual error message but not spam any
113
+ // further)
114
+ logger.info(
115
+ " First failure of an STDCM Simulation during the search (ignoring this possible path): ${e.message} "
116
+ )
117
+ }
118
+ nFailedSimulation++
119
+ null
120
+ }
121
+ }
122
+
123
+ /* *
124
+ * Log any relevant warnings about what happened during the processing, to be called once at the
125
+ * end. Aggregates events into fewer log entries.
126
+ */
127
+ fun logWarnings () {
128
+ if (nFailedSimulation > 0 )
129
+ logger.info(
130
+ " A total of $nFailedSimulation STDCM Simulations failed during the search (usually because of lack of traction)"
131
+ )
132
+ }
69
133
}
70
134
71
135
/* * Create an EnvelopeSimContext instance from the blocks and extra parameters. */
@@ -83,48 +147,6 @@ fun makeSimContext(
83
147
return build(rollingStock, envelopePath, timeStep, comfort)
84
148
}
85
149
86
- /* *
87
- * Returns an envelope matching the given block. The envelope time starts when the train enters the
88
- * block. stopPosition specifies the position at which the train should stop, may be null (no stop).
89
- *
90
- * Note: there are some approximations made here as we only "see" the tracks on the given blocks. We
91
- * are missing slopes and speed limits from earlier in the path.
92
- */
93
- fun simulateBlock (
94
- rawInfra : RawSignalingInfra ,
95
- infraExplorer : InfraExplorer ,
96
- initialSpeed : Double ,
97
- start : Offset <Block >,
98
- rollingStock : RollingStock ,
99
- comfort : Comfort ? ,
100
- timeStep : Double ,
101
- stopPosition : Offset <Block >? ,
102
- trainTag : String?
103
- ): Envelope ? {
104
- if (stopPosition != null && stopPosition == Offset <Block >(0 .meters))
105
- return makeSinglePointEnvelope(0.0 )
106
- val blockLength = infraExplorer.getCurrentBlockLength()
107
- if (start >= blockLength) return makeSinglePointEnvelope(initialSpeed)
108
- var stops = doubleArrayOf()
109
- var simLength = blockLength.distance - start.distance
110
- if (stopPosition != null ) {
111
- stops = doubleArrayOf(stopPosition.distance.meters)
112
- simLength = Distance .min(simLength, stopPosition.distance)
113
- }
114
- val path = infraExplorer.getCurrentEdgePathProperties(start, simLength)
115
- val envelopePath = EnvelopeTrainPath .from(rawInfra, path)
116
- val context = build(rollingStock, envelopePath, timeStep, comfort)
117
- val mrsp = computeMRSP(path, rollingStock, false , trainTag)
118
- return try {
119
- val maxSpeedEnvelope = MaxSpeedEnvelope .from(context, stops, mrsp)
120
- MaxEffortEnvelope .from(context, initialSpeed, maxSpeedEnvelope)
121
- } catch (e: OSRDError ) {
122
- // The train can't reach its destination, for example because of high slopes
123
- logger.info(" STDCM Simulation failed (ignoring this possible path): ${e.message} " )
124
- null
125
- }
126
- }
127
-
128
150
/* * Make an envelope with a single point of the given speed */
129
151
private fun makeSinglePointEnvelope (speed : Double ): Envelope {
130
152
return Envelope .make(
0 commit comments