From aeeae9d15db899cbcb1f8f9710cb9e642f91a35e Mon Sep 17 00:00:00 2001 From: Eloi Charpentier Date: Wed, 8 Jan 2025 17:35:37 +0100 Subject: [PATCH] core: stdcm: set a min speed for engineering allowance check We used to consider that we can add any amount of time if the train can basically stop, but this was too optimistic Signed-off-by: Eloi Charpentier --- .../stdcm/graph/EngineeringAllowanceManager.kt | 14 ++++++++++++-- .../osrd/stdcm/graph/PostProcessingSimulation.kt | 5 ++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/EngineeringAllowanceManager.kt b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/EngineeringAllowanceManager.kt index a6e8a66a45a..873ef8af9fa 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/EngineeringAllowanceManager.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/EngineeringAllowanceManager.kt @@ -141,13 +141,24 @@ class EngineeringAllowanceManager(private val graph: STDCMGraph) { // / // We need to set the first constant speed part to 0 // so that we can use it as floor constraint + + // The min speed value isn't entirely trivial to determine: + // We need it to be strictly positive to avoid NaN issues, + // but we're also too optimistic with allowance possibility + // when we let it get close to 0. But if it's too high, we miss + // out on solutions. + // So this is a magic value that could be tweaked if needed. + // + // Eventually, when we'll have actual capacity stops, we should + // use the actual minimum speed on the network. + val minSpeed = 1.0 builder.addPart( EnvelopePart.generateTimes( mutableListOf( EnvelopeProfile.CONSTANT_SPEED, ), doubleArrayOf(0.0, lastAccelerationPosition), - doubleArrayOf(1e-5, 1e-5) // >0 to avoid NaN time delta + doubleArrayOf(minSpeed, minSpeed) ) ) } @@ -168,7 +179,6 @@ class EngineeringAllowanceManager(private val graph: STDCMGraph) { if (slowdownPartBuilder.stepCount() > 1) slowdownBuilder.addPart(slowdownPartBuilder.build()) val slowestEnvelope = slowdownBuilder.build() - if (slowestEnvelope.minSpeed <= 1.0) return Double.POSITIVE_INFINITY return slowestEnvelope.totalTime } catch (e: OSRDError) { // We can be pessimistic: simulation error = no allowance diff --git a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/PostProcessingSimulation.kt b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/PostProcessingSimulation.kt index 1f364778f86..cd84564144e 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/PostProcessingSimulation.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/PostProcessingSimulation.kt @@ -407,11 +407,14 @@ private fun handlePostProcessingConflict( updatedTimeData: TimeData, fixedPoints: TreeSet, conflictOffset: Offset, - isMareco: Boolean + isMareco: Boolean, ): Envelope { postProcessingLogger.error( "Conflicts detected in post-processing, mismatch with the exploration data" ) + postProcessingLogger.error( + "NOTE: look through the logs for allowance issues, they may cause mismatches." + ) val conflictTime = fixedPoints.first { it.offset == conflictOffset }.time postProcessingLogger.info( " conflict happened at offset=$conflictOffset/${maxSpeedEnvelope.endPos.toInt()} " +