From 996d94ec04e543ca7758534e29ad0b4c93140da9 Mon Sep 17 00:00:00 2001 From: Eloi Charpentier Date: Mon, 7 Oct 2024 11:58:32 +0200 Subject: [PATCH] core: split margins at any scheduled point --- .../standalone_sim/StandaloneSimulation.kt | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/fr/sncf/osrd/standalone_sim/StandaloneSimulation.kt b/core/src/main/kotlin/fr/sncf/osrd/standalone_sim/StandaloneSimulation.kt index a58acab01fa..6842cf3acda 100644 --- a/core/src/main/kotlin/fr/sncf/osrd/standalone_sim/StandaloneSimulation.kt +++ b/core/src/main/kotlin/fr/sncf/osrd/standalone_sim/StandaloneSimulation.kt @@ -17,9 +17,8 @@ import fr.sncf.osrd.envelope_sim.EnvelopeSimContext import fr.sncf.osrd.envelope_sim.allowances.LinearAllowance import fr.sncf.osrd.envelope_sim.allowances.MarecoAllowance import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceRange -import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceValue.FixedTime -import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceValue.Percentage -import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceValue.TimePerDistance +import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceValue +import fr.sncf.osrd.envelope_sim.allowances.utils.AllowanceValue.* import fr.sncf.osrd.envelope_sim.pipelines.MaxEffortEnvelope import fr.sncf.osrd.envelope_sim.pipelines.MaxSpeedEnvelope import fr.sncf.osrd.envelope_sim_infra.EnvelopeTrainPath @@ -103,7 +102,14 @@ fun runStandaloneSimulation( // Provisional envelope: the train matches the standard allowances val provisionalEnvelope = if (margins.values.isEmpty()) maxEffortEnvelope - else buildProvisionalEnvelope(maxEffortEnvelope, context, margins, constraintDistribution) + else + buildProvisionalEnvelope( + maxEffortEnvelope, + context, + margins, + constraintDistribution, + schedule + ) // Final envelope: the train matches the standard allowances and given scheduled points val finalEnvelope = buildFinalEnvelope( @@ -379,7 +385,8 @@ fun buildProvisionalEnvelope( maxEffortEnvelope: Envelope, context: EnvelopeSimContext, rawMargins: RangeValues, - constraintDistribution: RJSAllowanceDistribution + constraintDistribution: RJSAllowanceDistribution, + schedule: List ): Envelope { val marginRanges = mutableListOf() // Add path extremities to boundaries @@ -387,6 +394,11 @@ fun buildProvisionalEnvelope( boundaries.add(Offset(Distance.ZERO)) boundaries.addAll(rawMargins.internalBoundaries) boundaries.add(Offset(Distance.fromMeters(context.path.length))) + + // These boundaries don't delimit different margin values, but they limit + // the ranges where they're applied + val extraBoundaries = schedule.map { it.pathOffset } + for (i in 0 until rawMargins.values.size) { val start = boundaries[i] val end = boundaries[i + 1] @@ -401,7 +413,7 @@ fun buildProvisionalEnvelope( is MarginValue.Percentage -> Percentage(rawValue.percentage) is MarginValue.None -> Percentage(0.0) } - marginRanges.add(AllowanceRange(start.distance.meters, end.distance.meters, value)) + marginRanges.addAll(splitAllowanceRange(extraBoundaries, start, end, value)) } val margin = if (constraintDistribution == RJSAllowanceDistribution.MARECO) @@ -410,6 +422,27 @@ fun buildProvisionalEnvelope( return margin.apply(maxEffortEnvelope, context) } +/** + * Add the allowance value over the given ranges, splitting it into different ranges for any + * boundary inside. + */ +fun splitAllowanceRange( + extraBoundaries: List>, + start: Offset, + end: Offset, + value: AllowanceValue +): Collection { + val res = mutableListOf() + val boundaries = extraBoundaries.filter { it > start && it < end } + var currentStart = start + for (boundary in boundaries) { + res.add(AllowanceRange(currentStart.distance.meters, boundary.distance.meters, value)) + currentStart = boundary + } + res.add(AllowanceRange(currentStart.distance.meters, end.distance.meters, value)) + return res +} + fun getStopPositions(schedule: List): List { return schedule.filter { it.stopFor != null }.map { it.pathOffset.distance.meters } }