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 88458dbd489..dc68eea38dc 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 @@ -7,6 +7,7 @@ import fr.sncf.osrd.envelope.part.EnvelopePart import fr.sncf.osrd.envelope.part.EnvelopePartBuilder import fr.sncf.osrd.envelope.part.constraints.EnvelopeConstraint import fr.sncf.osrd.envelope.part.constraints.EnvelopePartConstraintType +import fr.sncf.osrd.envelope.part.constraints.PositionConstraint import fr.sncf.osrd.envelope.part.constraints.SpeedConstraint import fr.sncf.osrd.envelope_sim.EnvelopeProfile import fr.sncf.osrd.envelope_sim.overlays.EnvelopeAcceleration @@ -117,7 +118,7 @@ class EngineeringAllowanceManager(private val graph: STDCMGraph) { ConstrainedEnvelopePartBuilder( speedupPartBuilder, SpeedConstraint(0.0, EnvelopePartConstraintType.FLOOR), - EnvelopeConstraint(maxEffort, EnvelopePartConstraintType.CEILING) + PositionConstraint(maxEffort.beginPos, maxEffort.endPos), ) EnvelopeAcceleration.accelerate( context, 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 97b5a4ca87a..181dcdeaa40 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 @@ -194,6 +194,25 @@ private fun initFixedPoints( } if (hasStandardAllowance && res.none { it.offset == length }) res.add(makeFixedPoint(res, edges, length, length, updatedTimeData, 0.0)) + + // Add points at the end of each engineering allowance + var prevEdgeLength = 0.meters + for (edge in edges) { + if (edge.afterEngineeringAllowance) { + if (res.none { it.offset.distance == prevEdgeLength }) { + res.add( + makeFixedPoint( + res, + edges, + Offset(prevEdgeLength), + length, + updatedTimeData, + ) + ) + } + } + prevEdgeLength += edge.length.distance + } return res } diff --git a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdge.kt b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdge.kt index f654a6c71c2..e2c43bd1200 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdge.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdge.kt @@ -34,6 +34,9 @@ data class STDCMEdge( // How long it takes to go from the beginning to the end of the block, taking the // standard allowance into account val totalTime: Double, + // Set to true if a conflict in the current edge required an engineering allowance. + // Used for initial placement of fixed time points in post-processing. + val afterEngineeringAllowance: Boolean, ) { val block = infraExplorer.getCurrentBlock() diff --git a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdgeBuilder.kt b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdgeBuilder.kt index 31f84594bcc..7ee219a5bd7 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdgeBuilder.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/stdcm/graph/STDCMEdgeBuilder.kt @@ -158,7 +158,9 @@ internal constructor( var maximumDelay = 0.0 var departureTimeShift = delayNeeded - if (delayNeeded > prevNode.timeData.maxDepartureDelayingWithoutConflict) { + val needEngineeringAllowance = + delayNeeded > prevNode.timeData.maxDepartureDelayingWithoutConflict + if (needEngineeringAllowance) { // We can't just shift the departure time, we need an engineering allowance // It's not computed yet, we just check that it's possible if (!graph.allowanceManager.checkEngineeringAllowance(prevNode, actualStartTime)) @@ -212,6 +214,7 @@ internal constructor( envelope!!.endSpeed, Length(fromMeters(envelope!!.endPos)), envelope!!.totalTime / standardAllowanceSpeedRatio, + needEngineeringAllowance, ) res = graph.backtrackingManager.backtrack(res!!, envelope!!) return if (res == null || graph.delayManager.isRunTimeTooLong(res)) null else res